一、事务概述
1.什么是事务
  一件事情有n个组成单元 要不这n个组成单元同时成功 要不n个单元就同时失败
就是将n个组成单元放到一个事务中
2.mysql的事务
  默认的事务:一条sql语句就是一个事务 默认就开启事务并提交事务
  手动事务:
    1)显示的开启一个事务:start transaction
    2)事务提交:commit代表从开启事务到事务提交 中间的所有的sql都认为有效真正的更新数据库
    3)事务的回滚:rollback 代表事务的回滚 从开启事务到事务回滚 中间的所有的sql操作都认为无效数据库没有被更新
    
二、JDBC事务操作
  默认是自动事务:
    执行sql语句:executeUpdate() ---- 每执行一次executeUpdate方法代表事务自动提交
  通过jdbc的API手动事务:
    开启事务:conn.setAutoComnmit(false);
    提交事务:conn.commit();
    回滚事务:conn.rollback();
     注意:控制事务的connnection必须是同一个
     执行sql的connection与开启事务的connnection必须是同一个才能对事务进行控制

三、DBUtils事务操作
1.QueryRunner
  有参构造:QueryRunner runner = new QueryRunner(DataSource dataSource);
   有参构造将数据源(连接池)作为参数传入QueryRunner,QueryRunner会从连接池中获得一个数据库连接资源操作数据库,所以直接使用无Connection参数的update方法即可操作数据库,即runner.update(sql)

int update(String sql); //sql=要执行的sql语句
int update(Connection conn, String sql);  //conn=使用的connection连接,sql=要执行的sql语句

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

2.因为使用事务,如果开启事务期间,同时有多个connection连接,则不能实现事务,因此如果使用DBUtils工具类,使用QueryRunner的有参构造的话,表示随机从连接池中选取,这样的话事务不能实现,所以必须使用QueryRunner的无参构造方法,然后创建一个Connection对象来使用。

Connection conn = null;
		try {
			QueryRunner runner = new QueryRunner();
			
			//runner.update("update account set money=15000 where name='tom'");
			//获得一个Connection
			conn = DataSourceUtils.getConnection();
			
			//开启事务
			conn.setAutoCommit(false);
			
			runner.update(conn, "update account set money=15000 where name='tom'");
			//提交或回滚事务
			conn.commit();
			
		} catch (SQLException e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}