事务的ACID原则:
原子性(Atomicaity) 事务执行过程中的任何失败都将导致事务所做的任何修改失效。
一致性(Consistency) 表示当事务执行失败时,所有被该事务影响的数据都应该恢复到事务执行前的状态。
隔离性(Isolation) 在事务执行过程中对数据的修改,在事务提交之前对其他事务不可见。
持久性(Durability) 当系统或介质发生故障时,确保已提交事务的更新不能丢失。
排它锁:事务设置排它锁后,该事务单独获得此资源,另一事务不能在此事务提交之前获得相同对象的共享锁或排它锁。
-行锁:当事务执行数据库插入、更新、删除操作时,该事务自动获得操作 表中操作行的排它锁。
示例代码(以下为一个简单的计数器,用作生产序列号):
//
为了说明问题重点,省略部分代码,时间只是假设
public int methodA() ... {
//行级琐使查找堵塞(methodC)
Counter counter = findByName();
counter.setCount(counter.getCount() + 1);
update(counter);//行级锁
}
public int methodB() ... {
//其他数据库操作
}
// 错误的例子(长事务)
public int methodC() ... {
beginTransaction();//开启事务
int conut = methodA(); //消耗300ms
methodB(); //消耗500ms
commitTransaction();//提交事务
}
在并发操作中methodC会一直等待,因为其他线程要查找回同一条记录,
已执行update操作的线程要等完成整个事务以后才把行级锁放开(获取count的动作造成堵塞)
共需要800ms
// 正确的例子(短事务)
public int methodD() ... {
beginTransaction();//开启事务
int conut = methodA(); //消耗300ms
commitTransaction();//提交事务
beginTransaction();//开启事务
methodB(); //消耗500ms
commitTransaction();//提交事务
}
public int methodA() ... {
//行级琐使查找堵塞(methodC)
Counter counter = findByName();
counter.setCount(counter.getCount() + 1);
update(counter);//行级锁
}
public int methodB() ... {
//其他数据库操作
}
// 错误的例子(长事务)
public int methodC() ... {
beginTransaction();//开启事务
int conut = methodA(); //消耗300ms
methodB(); //消耗500ms
commitTransaction();//提交事务
}
在并发操作中methodC会一直等待,因为其他线程要查找回同一条记录,
已执行update操作的线程要等完成整个事务以后才把行级锁放开(获取count的动作造成堵塞)
共需要800ms
// 正确的例子(短事务)
public int methodD() ... {
beginTransaction();//开启事务
int conut = methodA(); //消耗300ms
commitTransaction();//提交事务
beginTransaction();//开启事务
methodB(); //消耗500ms
commitTransaction();//提交事务
}
获取count的动作不会对其他线程造成堵塞
共需要300ms
共需要300ms
注意:事务要在尽可能短的时间内完成,尽可能不要在不同方法中实现事务的使用,因为方法嵌套多了,难免出现漏洞,
只是一个小的细节,都有可能会有很大的影响