一、事务特性
A 原子性:最小不可分割的单位(要么全成功,要么全失败)
B 一致性:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
比如转账,转账前两个账户的余额是1000,转账后两个账户的余额也是1000。
C 隔离性:多线程环境下,一个线程中的事务不能被其他线程中的事务打扰。
D 持久性:事务一旦提交,就应该被永久保存起来。
二、事务并发问题
A 脏读:读到了其他人正在操作的数据。
B 不可重复读:两次连续的读取,数据不一致。
C 幻(虚)读:一个线程中的事务读取到另一个线程中insert提交的数据。
三、事务的隔离级别(用来解决事务并发问题)
A 读未提交——可能出现 ABC
B 读已提交——BC
C 可重复读——C (MySQL默认级别)
D 串行化——没有问题,效率太低
四、在Hibernate中指定数据库的隔离级别
#hibernate.connection.isolation 1|2|4|8
使用一个字节指定隔离级别
0001 —— 1 (读未提交)
0010 —— 2 (读已提交)
0100 —— 4 (可重复读)
1000 —— 8 (串行化)
hibernate.cfg.xml
<!--指定hibernate操作数据库时的隔离级别-->(项目实际情况定隔离级别)
<property name=”hibernate.connection.isolation”>4</property>
五、在项目中如何管理事务
A 业务开始之前打开事务,业务执行之后提交事务。
执行过程中出现异常,回滚事务。
B 在DAO层操作数据库需要用到session对象。
在service控制事务也是使用session对象完成。我们需要确保DAO层和service层使用同一个session对象。
C 在hibernate中,确保使用同一个session的问题,
hibernate已经解决了,开发人员只需要调用sf.getCurrentSession()即可获得与当前线程绑定的session对象。
注意1:调用getCurrentSession方法必须配合主配置文件中的一段配置。
hibernate.cfg.xml
<property name=”hibernate.current_session_context_class”>thread</property>
public void function1() {
//每次返回与线程绑定的session
Session session1 = HibernateUtils.getCurrentSession();
Session session2 = HibernateUtils.getCurrentSession();
System.out.println(“session1 == session2”);//true
}
public void function2() {
//每次获得新的session
Session session1 =HibernateUtils.openSession();
Session session2 =HibernateUtils.openSession();
System.out.println(“session1 == session2”);//false
}
注意2:通过getCurrentSession()获得的session对象,当事务提交时,session会自动关闭,不要手动调用close关闭。
六、代码优化
public class CustomerDaoImpl implements CustomerDao {
public void save(Customer c) {
1.获得session
Sessionsession = HibernateUtils.openSession();
2.打开事务
Transactiontx = session.beginTransaction();
3.执行保存
session.save();
4.提交事务
tx.commit();
5.关闭资源
session.close();
}
}
public class CustomerDaoImpl implements CustomerDao {
public void save(Customer c) {
1.获得session
Session session = HibernateUtils.getCurrentSession();
2.执行保存
session.save();
}
}
public class CustomerServiceImpl implements CustomerService {
private CustomerDao customerDao = new CustomerDaoImpl();
public void save(Customer c) {
Session session = HibernateUtils.getCurrentSession();
1. 打开事务
Transaction tx =session.beginTransaction();
2. 调用Dao保存客户
try {
customerDao.save(c);
} catch (Exception e) {
e.printStackTrace();
3. 事务回滚
tx.rollback();
}
3. 关闭事务
tx.commit();
}
}