一、什么是事务? 要求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详解】_数据

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

添加主键冲突,报错后会进行回滚