2018-06-29 事务的提交与回滚

2018-06-29 事务的提交与回滚_第1张图片
05-ThreadLocal对象_[00-10-53][20180629-104717416].jpg

原子性,一致性,隔离性,持久性
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。
隔离性(Isolation)
事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

1.什么是事务
一件事情有n个组成单元 要不这n个组成单元同时成功 要不n个单元就同时失败
就是将n个组成单元放到一个事务中

2.mysql的事务
默认的事务:一条sql语句就是一个事务 默认就开启事务并提交事务
手动事务:
1)显示的开启一个事务:start transaction
2)事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效 真正的更新数据库
3)事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的 sql操作都认为无效数据库没有被更新

3、JDBC事务操作
默认是自动事务:
执行sql语句:executeUpdate() ---- 每执行一次executeUpdate方法 代表 事务自动提交
通过jdbc的API手动事务:
开启事务:conn.setAutoComnmit(false);
提交事务:conn.commit();
回滚事务:conn.rollback();
注意:控制事务的connnection必须是同一个
执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制

4、DBUtils事务操作
无参构造:QueryRunner runner = new QueryRunner();
无参的构造没有将数据源(连接池)作为参数传入QueryRunner,那么我们在使 用QueryRunner对象操作数据库时要使用有Connection参数的方法

https://blog.csdn.net/lutianfeiml/article/details/51424084

银行转账有个问题::

我的connection要在dao层设置连接,但是connection的事务控制要在service层,并且service层和dao层的connection要是同一个。下面代码是不对的。


import java.sql.Connection;
import java.sql.SQLException;

import javax.sql.DataSource;

import com.ryan.dao.TransferDao;
import com.ryan.utils.DataSourceUtils;

public class TransferService {

    public boolean transfer(String out, String in, double money)  {
        TransferDao dao=new TransferDao();
        boolean isTransferSuccess=true;
        Connection connection=null;
        /*方法结束,池子会自动帮你关闭连接。  池子关上了,代表什么都没有了,事务结束了
         * 这个时候,如果别人拿到这个conn,要重新开启一个新的连接,需要重新开启新的事务*/
        try {
            connection=DataSourceUtils.getConnection();
            connection.setAutoCommit(false);
            dao.out(connection,out,money);
            
            dao.in(connection,in,money);[图片上传中...(05-ThreadLocal对象_[00-10-53][20180629-104717416].jpg-25ff8c-1530240471553-0)]

        } catch (SQLException e) {
            try {
                isTransferSuccess=false;
                connection.rollback();
            } catch (SQLException ex) {             
                ex.printStackTrace();
            }           
            e.printStackTrace();
        }finally {
            try {
                connection.commit();
            } catch (SQLException e) {              
                e.printStackTrace();
            }
        }
        
        return isTransferSuccess;
    }

}

所以要解决这个问题 要用 ThreadLocal

每一个ThreadLocal都是一个map,只是它的key就是当前线程的名字,值就是ThreadLocal存的内容。

package com.itheima.transfer.service;

import java.sql.Connection;
import java.sql.SQLException;

import com.itheima.transfer.dao.TransferDao;
import com.itheima.utils.DataSourceUtils;
import com.itheima.utils.MyDataSourceUtils;

public class TransferService {

    public boolean transfer(String out, String in, double money) {
        
        TransferDao dao = new TransferDao();
        
        boolean isTranferSuccess = true;
        //Connection conn = null;
        try {
            
            //开启事务
            //conn = DataSourceUtils.getConnection();
            //conn.setAutoCommit(false);
            
            //开启事务
            MyDataSourceUtils.startTransaction();
            
            //转出钱的方法  
            dao.out(out,money);
            //int i = 1/0;
            //转入钱的方法
            dao.in(in,money);
            
        } catch (Exception e) {
            isTranferSuccess = false;
            //回滚事务
            try {
                MyDataSourceUtils.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally{
            try {
                MyDataSourceUtils.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        return isTranferSuccess;
        
    }

}

package com.itheima.transfer.dao;

import java.sql.Connection;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

import com.itheima.utils.DataSourceUtils;
import com.itheima.utils.MyDataSourceUtils;

public class TransferDao {

    public void out(String out, double money) throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection conn = MyDataSourceUtils.getCurrentConnection();
        String sql = "update account set money=money-? where name=?";
        runner.update(conn, sql, money,out);
    }

    public void in(String in, double money) throws SQLException {
        QueryRunner runner = new QueryRunner();
        Connection conn = MyDataSourceUtils.getCurrentConnection();
        String sql = "update account set money=money+? where name=?";
        runner.update(conn, sql, money,in);
    }

}

package com.itheima.utils;

import java.sql.Connection;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class MyDataSourceUtils {

    //获得Connection ----- 从连接池中获取
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
    
    //创建ThreadLocal
    private static ThreadLocal tl = new ThreadLocal();
    
    //开启事务
    public static void startTransaction() throws SQLException{
        Connection conn = getCurrentConnection();
        conn.setAutoCommit(false);
    }
    
    //获得当前线程上绑定的conn
    public static Connection getCurrentConnection() throws SQLException{
        //从ThreadLocal寻找 当前线程是否有对应Connection
        Connection conn = tl.get();
        if(conn==null){
            //获得新的connection
            conn = getConnection();
            //将conn资源绑定到ThreadLocal(map)上
            tl.set(conn);
        }
        return conn;
    }
    
    public static Connection getConnection() throws SQLException{
        return dataSource.getConnection();
    }

    //回滚事务
    public static void rollback() throws SQLException {
        getCurrentConnection().rollback();
    }

    //提交事务
    public static void commit() throws SQLException {
        Connection conn = getCurrentConnection();
        conn.commit();
        //将Connection从ThreadLocal中移除
        tl.remove();
        conn.close();
        
    }

}

你可能感兴趣的:(2018-06-29 事务的提交与回滚)