Java操作数据库(三,趣味理解JDBC事务)

Posted 韶光不负

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java操作数据库(三,趣味理解JDBC事务)相关的知识,希望对你有一定的参考价值。

如果读者对此篇文章有不解可以查看小编JDBC分区下的文章哦,欢迎大家点赞与收藏!

目录

 事务

事务的讲解小编准备从一个故事进行讲起:

创建一个银行(数据库创建,张三:100000,小明:0)

 模拟银行交易(jdbc模拟)

突然发生意外了,程序收钱了,但没有转账给小明 

第一种情况(时间上有延迟,转账后几分钟到)

 第二种情况 程序内部出现问题(钱没了)

结论(记住)

解决办法(在实际开发中,把JDBC的自动提交机制关闭,改为手动提交,三步骤)

第一,先把事务改成手动提交(setAutoCommit(false))

第二,手动提交,关闭事务(commit())

第三步,出现问题,程序进行回滚(rollback())

完整代码


 事务

事务的讲解小编准备从一个故事进行讲起:

话说在很久很久以前发生这样一个故事,地主张三在银行门口打钱给自己儿子小明,自己账户上有100000元,小明没有钱,张三打了50000给儿子,然后就发生了下面这样的事。

创建一个银行(数据库创建,张三:100000,小明:0)

create table t_bank(
	 id int primary key auto_increment ,
	 u_name varchar(20) not null ,
 	 money double(10,2)
-- 10是有效数子,2是小数的位数  
);
insert into t_bank(u_name , money) value ("zhangsan",100000);
insert into t_bank (u_name,money) value ("xiaoming",0);
select * from t_bank;

 模拟银行交易(jdbc模拟)

package com.luosf.jdbc;

import java.sql.*;


/**
模拟银行转账

 */
public class Jdbc_Transfer 
    public static void main(String[] args) 
            transfer();
    
    static void transfer()
        Connection conn = null;
        PreparedStatement prestat = null;
        ResultSet res = null;


        try 
            //1,创建驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2,链接数据库
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");

            //3,获取预编译数据库操作对象
            String sql = "update t_bank set money = ? where u_name = ? ";


            //此时发送sql语句给DBMS,进行sql语句的编译
             prestat = conn.prepareStatement(sql);

             //张三给小明转账
             prestat.setDouble(1,50000);
             prestat.setString(2,"zhangsan");

             int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;

             //小明账户到账
            prestat.setDouble(1,50000);
            prestat.setString(2,"xiaoming");
            count += prestat.executeUpdate();  //再次更新,count+1,count=2

            System.out.println(count == 2 ? "转账成功" : "转账失败");




         catch (Exception e) 
            e.printStackTrace();
        finally 
            //释放资源
            if (res != null)
                try 
                    res.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (prestat != null)
                try 
                    prestat.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (conn != null)
                try 
                    conn.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
        
    

这样就转账完成了

突然发生意外了,程序收钱了,但没有转账给小明 

第一种情况(时间上有延迟,转账后几分钟到)

张三给小明打电话,我钱打给你了,你看看,小明一看,我靠,明没钱这个月要吃土了!

实现

 Thread.sleep(20000); //休息20秒,模拟断电了

看看

package com.luosf.jdbc;

import java.sql.*;


/**
模拟银行转账

 */
public class Jdbc_Transfer 
    public static void main(String[] args) 
            transfer();
    
    static void transfer()
        Connection conn = null;
        PreparedStatement prestat = null;
        ResultSet res = null;


        try 
            //1,创建驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2,链接数据库
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");

            //3,获取预编译数据库操作对象
            String sql = "update t_bank set money = ? where u_name = ? ";


            //此时发送sql语句给DBMS,进行sql语句的编译
             prestat = conn.prepareStatement(sql);

             //张三给小明转账
             prestat.setDouble(1,50000);
             prestat.setString(2,"zhangsan");

             int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;

            Thread.sleep(20000); //休息20秒,模拟断电了
            //小明账户到账
            prestat.setDouble(1,50000);
            prestat.setString(2,"xiaoming");
            count += prestat.executeUpdate();  //再次更新,count+1,count=2

            System.out.println(count == 2 ? "转账成功" : "转账失败");




         catch (Exception e) 
            e.printStackTrace();
        finally 
            //释放资源
            if (res != null)
                try 
                    res.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (prestat != null)
                try 
                    prestat.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (conn != null)
                try 
                    conn.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
        
    

 第二种情况 程序内部出现问题(钱没了)

    String s = null;
    s.toString();//创建空指针异常
package com.luosf.jdbc;

import java.sql.*;


/**
模拟银行转账

 */
public class Jdbc_Transfer 
    public static void main(String[] args) 
            transfer();
    
    static void transfer()
        Connection conn = null;
        PreparedStatement prestat = null;
        ResultSet res = null;


        try 
            //1,创建驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2,链接数据库
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");

            //3,获取预编译数据库操作对象
            String sql = "update t_bank set money = ? where u_name = ? ";


            //此时发送sql语句给DBMS,进行sql语句的编译
             prestat = conn.prepareStatement(sql);

             //张三给小明转账
             prestat.setDouble(1,50000);
             prestat.setString(2,"zhangsan");

             int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;

//            Thread.sleep(20000); //休息20秒,模拟断电了
            String s = null;
            s.toString();//创建空指针异常
            //小明账户到账
            prestat.setDouble(1,50000);
            prestat.setString(2,"xiaoming");
            count += prestat.executeUpdate();  //再次更新,count+1,count=2

            System.out.println(count == 2 ? "转账成功" : "转账失败");




         catch (Exception e) 
            e.printStackTrace();
        finally 
            //释放资源
            if (res != null)
                try 
                    res.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (prestat != null)
                try 
                    prestat.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (conn != null)
                try 
                    conn.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
        
    

 

结论(记住)

JDBC默认情况下是支持自动进行提交的JDBC执行一条语句就提交一次。(自动提交:执行一条DML,就自动提交一次)

解决办法(在实际开发中,把JDBC的自动提交机制关闭,改为手动提交,三步骤)

进行完一个完整的事务后,全部再一起提交。

第一,先把事务改成手动提交(setAutoCommit(false))

 

 

应该在获取链接对象后,就关闭自动提交机制

//开启事务,将自动提交改变成手动提交
 conn.setAutoCommit(false);

第二,手动提交,关闭事务(commit())

 //当前面的代码都没有问题,能执行到这,commit()关闭事务,手动提交
 conn.commit();

第三步,出现问题,程序进行回滚(rollback())

回滚:简单理解就是倒退,返回最初始的状态

//出现异常,保证安全性,程序进行回滚 
try 
       if (conn != null)
             //防止conn出现空指针异常,先进行判断一下
              conn.rollback();
             
     

完整代码

package com.luosf.jdbc;

import java.sql.*;


/**
模拟银行转账

 */
public class Jdbc_Transfer 
    public static void main(String[] args) 
            transfer();
    
    static void transfer()
        Connection conn = null;
        PreparedStatement prestat = null;
        ResultSet res = null;


        try 
            //1,创建驱动
            Class.forName("com.mysql.jdbc.Driver");

            //2,链接数据库
            conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3333/db_nhjc?charset=utf-8","root","root");

            //开启事务,将自动提交改变成手动提交
            conn.setAutoCommit(false);
            //3,获取预编译数据库操作对象
            String sql = "update t_bank set money = ? where u_name = ? ";


            //此时发送sql语句给DBMS,进行sql语句的编译
             prestat = conn.prepareStatement(sql);

             //张三给小明转账
             prestat.setDouble(1,50000);
             prestat.setString(2,"zhangsan");

             int count = prestat.executeUpdate();//跟新数据库,当跟新完成后,count+1;

//            Thread.sleep(20000); //休息20秒,模拟断电了
            String s = null;
            s.toString();//创建空指针异常
            //小明账户到账
            prestat.setDouble(1,50000);
            prestat.setString(2,"xiaoming");
            count += prestat.executeUpdate();  //再次更新,count+1,count=2

            System.out.println(count == 2 ? "转账成功" : "转账失败");


            //当前面的代码都没有问题,能执行到这,commit()关闭事务,手动提交
            conn.commit();

         catch (Exception e) 
            //出现异常,保证安全性,程序进行回滚
            try 
                if (conn != null)
                    //防止conn出现空指针异常,先进行判断一下
                    conn.rollback();
                    
             catch (SQLException throwables) 
                throwables.printStackTrace();
            
            e.printStackTrace();
        finally 
            //释放资源
            if (res != null)
                try 
                    res.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (prestat != null)
                try 
                    prestat.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
            if (conn != null)
                try 
                    conn.close();
                 catch (SQLException throwables) 
                    throwables.printStackTrace();
                
            
        
    

测试

 

 

以上是关于Java操作数据库(三,趣味理解JDBC事务)的主要内容,如果未能解决你的问题,请参考以下文章

Java总结(随笔)——代码总结JDBC以及事务,以银行转账,查账等为例

Java数据库连接——JDBC调用存储过程,事务管理和高级应用

Java -- JDBC 学习--事务

java 事务

Spring事务JDBC方式下的事务使用示例

有关jdbc以及JDBC事务的相关操作