【Java事务提交与回滚(rollback,setAutoCommit,commit)Transaction详解】

一、什么是事务?

要求MySQL的表类型为Innodb才支持事务。使用事务时,要求数据库引擎必须是 InnoDB 引擎
在数据库操作中,一项事务是由一条或多条对数据库更新的sql语句,所组成的一个不可分割的工作单元
只有当事务中的所有操作都正常完成了,整个事务才能被提交到数据库,如果有一项操作没有完成,就必须撤消整个事务。
例如:
在银行的转帐事务中,假定张三从自己的帐号上把1000元转到李四的帐号上,相关的sql语句如下:
update account set monery=monery-1000 where name=‘zhangsan’ ;
update account set monery=monery+1000 where name=‘lisi’ ;
这个两条语句必须作为一个完成的事务来处理。只有当两条都成功执行了,才能提交这个事务。如果有一句失败,整个事务必须撤消。

二、事务的特点:

原子性、一致性、隔离性和持久性。(一句话:一个业务要么全部成功,要么全部失败。)
原子性: 表示事务执行过程中,用户定义的操作序列要么全部执行成功,要么全部执行失败。
一致性: 表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态,这称为事务回滚。
隔离性: 表示在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
持久性: 表示事务完成之后,对系统的影响是永久性的。如果已提交的数据在事务执行失败时,数据的状态都应该正确。

三、JDBC实现事务方式:

1、保证一个业务的所有更新操作中。所使用的连接对象是同一个连接对象
2、将连接对象的提交方式设置为手动提交。
​ connection.setAutoCommit(false);
​ 通过 connection.commit();提交事务
​ 如果有异常发送时,可以通过connection.rollback();回滚事务
注意:控制事务的connnection必须是同一个

四、事务的并发问题

当两个或两个以上的线程,同时访问同一条记录时,就存在事务并发问题,可能造成数据混乱。
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的就是脏数据。
2、不可重复读:事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一致。
3、幻读:事务A对数据库的数据进行批量操作。事务B完成记录的添加,这时新加的记录可能就没有进行事务A的批量操作。这就是幻读。
解决事务并发问题,需要采用事务隔离级别来进行

五、代码实现事务的提交和回滚详细过程

Transaction示例:

// 示例
public class TransactionRollBackController extends ServicePluginAdapter{
    public static final Logger logger = LoggerFactory.getLogger(TransactionRollBackController.class);

    @Override
    public Object executeProcessService(ESPServerContext espContext, Object responseObject) throws Exception {
        JParamObject po = espContext.getParamObject();
        JResponseObject RO = espContext.getResponseObject();
        try {
            // 获取数据
            String ybDctId = po.GetValueByParamName("ybDctId", "ATEST2");
            String mbDctId = po.GetValueByParamName("mbDctId", "ATEST1");
            if (StringUtils.isBlank(mbDctId)) {
                return null;
            } else {
                // 根据字典表,先进行删除数据(先删除mbDctId,在根据ybDctId数据更新mbDctId数据)
                operateDbData(espContext, ybDctId, mbDctId);
                return RO;
            }
        } catch (Exception e) {
            // 日志中心能接受到日志
            logger.error(e.getMessage());
            // 平台封装的异常类
            ServiceException se = new ServiceException(e.getMessage());
            se.setErrorMessage(e.getMessage());
            // -1:异常;0:正常
            se.setErrorCode(-1);
            // 主要为了前台出现提示框
            throw se;
        }
    }

    /**
     * 功能描述:
     * 进行数据操作
     *
     * @param espContext
     * @param ybDctId    源表名
     * @param mbDctId    目标表名
     */
    private void operateDbData(ESPServerContext espContext, String ybDctId, String mbDctId) throws SQLException {
        JConnection connection = null;
        PreparedStatement pSt = null;
        // 设置回滚位置
        Savepoint savepoint = null;

        try {
            // 获取连接
            connection = espContext.getConnection();
            // 关闭自动提交事务
            connection.setAutoCommit(false);
            // 组织删除数据
            StringBuilder deleteSql = new StringBuilder();
            deleteSql.append("DELETE FROM ").append(mbDctId).append(" WHERE F_BH = '1'");
            // 编译
            pSt = connection.prepareStatement(deleteSql.toString());
            // 删除数据
            pSt.executeUpdate();

            // ============================================================
            //设置回滚的点  失败只会回滚users信息
            //savepoint = connection.setSavepoint("检查点");
            // ============================================================

            // 根据源表添加数据到目标表
            StringBuilder upDateSql = new StringBuilder();
            // INSERT INTO 目标表 SELECT * FROM 来源表 ;
            upDateSql.append("INSERT INTO ").append(mbDctId).append(" SELECT * FROM ").append(ybDctId);
            // 编译
            pSt = connection.prepareStatement(upDateSql.toString());
            // 添加数据
            pSt.executeUpdate();

            // =============================================================

            //成功: 提交事务。
            connection.commit();


//                // 批量提交时
//                // 1、积攒sql
//                preparedStatement.addBatch();
//                // 进行批量处理
//                if (i % 600 == 0 && i != 0) {
//                    // 2、攒够之后提交一次,与数据库交互一次
//                    preparedStatement.executeBatch();
//                    // 清空缓存数据
//                    preparedStatement.clearBatch();
//                }
//            }
//            preparedStatement.executeBatch();
//            // 提交
//            conn.commit();
//            preparedStatement.clearBatch();
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                //事变: 回滚事务
                connection.rollback();
                // 回滚到指定位置
                // savepoint = conn.setSavepoint("检查点");
            } catch (Exception e1) {
                e1.printStackTrace();
            }
        } finally {
            //关闭连接
            JConnection.BackStatement(pSt, null);
        }
    }
}

【Java事务提交与回滚(rollback,setAutoCommit,commit)Transaction详解】_第1张图片
【Java事务提交与回滚(rollback,setAutoCommit,commit)Transaction详解】_第2张图片
添加主键冲突,报错后会进行回滚!!!

你可能感兴趣的:(Java,java,数据库,开发语言)