一、事务的四大特性(ACID)
1、原子性(atomicity):组成事务的语句形成了一个逻辑单元,不能只执行一部分;
2、一致性(consistency):在事务处理执行前后,数据库与理论值是一致的(数据库完整性约束);
3、隔离性(isolcation):一个事务处理和另一个事务处理相互间互不影响;
4、持续性(durability):事务处理的效果能够被永久保存下来。
二、隔离级别
1、多线程并发执行可能会产生以下三个问题:
脏读(dirtyreads):一个事务读取了另一个事务未提交的并行事务写的数据;
不可重复读(non-repeatablereads):一个事务重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务修改过;
幻读(phantomread):一个事务重新执行一个查询,返回一套符合条件的行,发现这些行因为最近提交的事务而发生了改变
2、隔离级别
读未提交(Read uncommitted):未解决
读已提交 (Readcommitted):已解决:脏读
可重复读 (Repeatableread):已解决:脏读,不可重复读
序列化 (Serializble):已解决:脏读,不可重复读,幻读
3、设置隔离级别
connection.setTransactionlsolation(Connection.事务级别)
MySql默认为度已提交;
三、基本操作
1、connection.setAutCommit(false):关闭事务自动提交
2、connection.commit():手动提交事务
3、connection.rollback():事务回滚
补:撤销事务中的部分操作
SavePoint sp = connection.setSavepoint();:设置事务回滚点
connection.rollback(sp);
connection.commit();:最后不要忘了提交事务,否则前面需要提交保存的操作也将不会保存到数据库中
代码示例:(修改学生并更新班级)
StudentDao.java:
1 public void updateStudent(Connection conn,Student s) throws SQLException{
2 String sql = "update student set name = ?,age = ?,sex = ?,clazzid = ? where id = ?";
3 try {
4 st = conn.prepareStatement(sql);
5 st.setString(1, s.getName());
6 st.setInt(2, s.getAge());
7 st.setString(3, s.getSex());
8 st.setInt(4, s.getClazz().getId());
9 st.setInt(5, s.getId());
10 } catch (SQLException e) {
11 e.printStackTrace();
12 }
13 /*上面只捕获st = conn.prepareStatement(sql);的异常
14 * st.executeUpdate();最后将执行对数据库更改的操作产生的异常抛出到上一层(Service)调用者
15 * connection开启事务在Service中开启
16 * 所以Connection来自Service中开启事务的连接
17 */
18 st.executeUpdate();
19 }
ClazzDao.java:
1 //为学生所转到的新班级增加一个人数
2 public void addClazzCount(Connection conn,int clazzid) throws SQLException{
3 String sql = "update clazz set count = count + 1 where id =?";
4 try {
5 st = conn.prepareStatement(sql);
6 st.setInt(1, clazzid);
7 } catch (SQLException e) {
8 e.printStackTrace();
9 }
10 /*上面只捕获st = conn.prepareStatement(sql);的异常
11 * st.executeUpdate();最后将执行对数据库更改的操作产生的异常抛出到上一层(Service)调用者
12 * connection开启事务在Service中开启
13 * 所以Connection来自Service中开启事务的连接
14 */
15 st.executeUpdate();
16 }
17 //为学生原来所在的班级减少一个人数
18 public void subClazzCount(Connection conn,int clazzid) throws SQLException{
19 String sql = "update clazz set count = count -1 where id =?";
20 try {
21 st = conn.prepareStatement(sql);
22 st.setInt(1, clazzid);
23 } catch (SQLException e) {
24 e.printStackTrace();
25 }
26 /*上面只捕获st = conn.prepareStatement(sql);的异常
27 * st.executeUpdate();最后将执行对数据库更改的操作产生的异常抛出到上一层(Service)调用者
28 * connection开启事务在Service中开启
29 * 所以Connection来自Service中开启事务的连接
30 */
31 st.executeUpdate();
32 }
重点来了!
Service中开启,提交,回滚事务
Service.java
1 //更新学生信息
2 public void update(Student s) {
3 Connection connection = JDBCUtil_C3P0.getConnection();
4 try {
5 //关闭事务自动提交(开启事务)
6 connection.setAutoCommit(false);
7 //在数据库中查找学生原本所在班级
8 int oldclazzid = studentDao.findById(s.getId()).getClazz().getId();
9 //如果学生班级发生改变,对班级表进行修改
10 if(oldclazzid !=s.getClazz().getId()){
11 //为转到的新班级增加一个学生
12 clazzDao.addClazzCount(connection, s.getClazz().getId());
13 //为原本所在的旧班级减少一个学生
14 clazzDao.subClazzCount(connection, oldclazzid);
15 //测试事务,手动抛出一个SQL异常
16 //throw new SQLException("操作异常");
17 }
18 //修改学生信息
19 studentDao.updateStudent(connection, s);
20 //以上所有操作无异常则提交事务
21 connection.commit();
22
23 } catch (SQLException e) {
24 e.printStackTrace();
25 //一旦事务中有哪一步操作发生异常则进行事务回滚
26 try {
27 connection.rollback();
28 } catch (SQLException e1) {
29 e1.printStackTrace();
30 }
31 }finally{
32 //关闭连接资源
33 clazzDao.close(connection);
34 studentDao.close(connection);
35 }
36
37 }
Over