Java实战之02Hibernate-06处理并发
十三、处理并发
1、事务的隔离级别
不考虑隔离级别出现的问题:
脏读:一个线程中的事务读到了另外一个线程中未提交的数据。
不可重复读:一个线程中的事务读到了另外一个线程中提交的update(更新)的数据。
虚读:一个线程中的事务读到了另外一个线程中提交的insert(插入)的数据。
事务的隔离级别:
1:READ UNCOMMITTED:脏读、不可重复读、虚读(幻读)都可能发生。
2:READ COMMITTED:避免脏读;不可重复读、虚读(幻读)都可能发生。
4:REPEATABLE READ:避免脏读、不可重复读,虚读(幻读)可能发生。
8:SERIALIZABLE:避免脏读、不可重复读、虚读(幻读)。
通过配置参数hibernate.connection.isolation=1|2|4|8进行设置。MySQL:默认4 Oracle:默认2
2、第二类更新丢失
//线程1
@Test
public void test1(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Customer c1 = s.get(Customer.class, 1);
c1.setName("泰斯特");
tx.commit();
s.close();
} //线程2
@Test
public void test2(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Customer c1 = s.get(Customer.class, 1);
c1.setAge(20);
tx.commit();
s.close();
}
3、解决丢失更新的方案
3.1、悲观锁(不是锁,是一种处理态度。是hibernate的)
Hibernate认为丢失更新现象一定会发生。悲观锁用的是数据库的锁机制。(独占模式效率肯定不会高)
数据库的锁机制:(是真正的锁)
共享锁:可以有多把锁。
MySQL客户端线程1 |
MySQL客户端线程2 |
开启事务 strat transaction; |
开启事务 strat transaction; |
执行查询:select * from customes where id = 1 lock in share mode; 加共享锁 |
执行查询:select * from customes where id = 1 lock in share mode; 加共享锁 |
执行更新:update customers set name='张三' where id = 1; 此时会自动加排他锁。但是由于线程2没有释放共享锁,所以线程1处于等待状态。 |
commit; 当线程2释放共享锁,线程1就可以执行成功了。 |
排他锁(独占模式,也称为独占锁):只能有一把锁,在锁之前,不能有任何的锁。执行写操作(insert,update,delete)的时候会自动加锁。
MySQL客户端线程1 |
MySQL客户端线程2 |
开启事务 strat transaction; |
开启事务 strat transaction; |
执行查询:select * from customes where id = 1 for update; 加排他锁 |
执行查询:select * from customes where id = 1 lock in share mode ; 由于有线程1的排他锁存在,线程2将处于等待状态 |
执行更新:update customers set age = 50 where id = 1; 此时还没有释放排他锁 |
|
提交事务(释放排他锁) commit; |
线程2显示查询结果,已经是线程1改过之后的数据了。 |
死锁:DEADLOCK
MySQL客户端线程1 |
MySQL客户端线程2 |
开启事务 strat transaction; |
开启事务 strat transaction; |
执行查询:select * from customes where id = 1 lock in share mode; 加共享锁 |
执行查询:select * from customes where id = 1 lock in share mode; 加共享锁 |
执行更新:update customers set name='张三' where id = 1; 此时会自动加排他锁。但是由于线程2没有释放共享锁,所以线程1处于等待状态。 |
执行更新:update customers set age=18 where id = 1; 此时会自动加排他锁。但是由于线程1没有释放共享锁,所以线程2处于等待状态。 |
结果:线程1等着线程2释放共享锁,而线程2等着线程1释放排他锁。就造成了死锁。 |
//线程1
@Test
public void test1(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Customer c1 = s.get(Customer.class, 1,LockMode.PESSIMISTIC_WRITE);//hibernate处理丢失更新的悲观锁解决方式
//Customer c1 = s.get(Customer.class, 1);
c1.setName("泰斯特");
tx.commit();
s.close();
} //线程2
@Test
public void test2(){
Session s = HibernateUtil.getSession();
Transaction tx = s.beginTransaction();
Customer c1 = s.get(Customer.class, 1,LockMode.PESSIMISTIC_WRITE);
//Customer c1 = s.get(Customer.class, 1);
c1.setAge(20);
tx.commit();
s.close();
}
3.2、乐观锁(不是锁,是一种处理态度)
Hibernate认为丢失更新现象不一定会发生。乐观锁使用的是版本号机制。
private Integer id;
private String name;
private Integer age;
//================版本号==================
private Integer version;
//=======================================
//一对多关系映射:一个客户可以有多个订单
private Set<Order> orders = new HashSet<Order>(0); public Customer(){ }
<class name="Customer" table="T_CUSTOMERS">
<id name="id" column="id">
<generator class="native"></generator>
</id>
<!-- 版本字段,用于解决丢失更新 -->
<version name="version"></version> <property name="name" column="NAME"></property>
<property name="age" column="AGE"></property>
<!-- 一对多关系映射:
set元素:
作用:映射集合元素
属性:
name:映射实体类中的集合属性
table:指定对应的表
key元素:它是set的子元素
作用:就是用于指定外键的
属性:
column:指定外键字段的名称
one-to-many元素:它是set的子元素
作用:描述当前实体映射文件和set中指定属性之间的关系。
属性:
class:指定是从表的实体类名称
-->
<set name="orders" table="T_ORDERS" >
<key column="CUSTOMER_ID"></key>
<one-to-many class="Order"/>
</set>
</class>
最新文章
- 如何在高并发分布式系统中生成全局唯一Id
- C#开发微信门户及应用(10)--在管理系统中同步微信用户分组信息
- 存储过程 Row_number() 分页
- DOM编程 删除节点
- 条件注释判断浏览器版本<;!--[if lt IE 9]>;
- mouseover和mouseout多次触发解决方法(兼容ie和firefox)(转)
- hdu 1622 Trees on the level
- poj 3264 Balanced Lineup(线段树、RMQ)
- Oracle Hint用法总结
- php下正则表达式整理
- c语言输入输出函数
- thinkphp框架相关研究(一)
- chain pattern
- Unity3D ——强大的跨平台3D游戏开发工具(四)
- Winform控件根据文字内容自动调整最合适大小
- Java课程设计——学生信息系统(团队)
- python-简单邮件报警
- Spark-shell错误:Missing Python executable &#39;python&#39;, defaulting to ...
- python selenium打开新窗口,多窗口切换
- [从零开始搭网站八]CentOS使用yum安装Redis的方法
热门文章
- position绝对剧中
- 【Stage3D学习笔记续】山寨Starling(五):纹理计算和尺寸计算
- (10.09作业)学生选课数据库SQL语句练习题
- JS单词形式的运算符
- 安卓开发21:深入理解Handler
- Yale CAS + .net Client 实现 SSO 的完整版
- C++ “读取位置 0x****** 时发生访问冲突”的可能原因
- Win7家庭普通版、家庭高级版、专业版、旗舰版版本差别
- HTML5 面试中最常问到的 10 个问题
- JAVA获取CLASSPATH路径--转