- 浏览: 6766043 次
- 性别:
- 来自: 武汉
-
文章分类
最新评论
-
逐客叫我:
看完了懵了,一会原生方法栈一会堆,自己都不用一套。
深入JVM系列(一)之内存模型与内存分配 -
xhwahaha:
import java.util.Arrays;public ...
腾讯的一个面试题 -
j00131120:
总结的非常不错
从员工到总监,你要明白的8个道理 -
Will.Du:
这是thinking in java的例子吧
对象序列化 -
ping22changxin:
能否借你事例源码学习一下,谢谢了:812185421@qq.c ...
ActiveMQ发送ObjectMessage的一个问题
hibernate 控制并发访问
在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同:
◆未授权读取(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个数据则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
◆授权读取(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
◆可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
◆序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
如果一个事务读取由另一个还没有被提交的事务进行的改变,就发生脏读取(dirty read)。这很危险,因为由其他事务进行的改变随后
可能回滚,并且低一个事务可能编写无效的数据。
如果一个事物读取一个行两次,并且每次读取不同的状态,就会发生不可重复读取(unrepeatable read)。例如,另一个事务可能已经
写到这个行,并已经在两次读取之间提交。
不可重复读取的一个特殊案例是二次丢失更新问题(second lost updates problem)。想象两个并发事务都读取一个行:一个写到行并
提交,然后第二个也写到行并提交。有第一个事务所做的改变丢失了。
幻读(phantom read)发生在一个事务执行一个查询两次,并且第二个结果集包括第一个结果集中不可见的行,或者包括已经删除的行时。
这种情况是由另一个事务在两次查询执行之间插入或者删除行照成的。
ANSI事务隔离性级别:
允许脏读取但不允许丢失更新的系统,要在读取未提交(read uncommitted)的隔离性中操作。如果一个为提交事务已经写到一个行,
另一个事务就不可能再写到这个行。但任何事务都可以读取任何行。这个隔离性级别可以在数据库管理系统中通过专门的写锁来实现。
允许不可重复读取但不允许脏读取系统,要实现读取提交(read committed)的事务隔离性。这可以用共享的读锁和专门的写锁来实现。
读取事务不会阻塞其他事务访问行。但是为提交的鞋事务隔赛所有其他的事务访问改行。
在可重复读(repeatable read)隔离性模式中操作的系统既不允许不可重复读取,也不允许脏读取。幻读可能发生。
可序列化 (serializable)提供最严格的事务隔离性。这个隔离性级别模拟连续的事务执行,好像事务是连续的一个接一个的执行,而不是
并发的执行。
选择隔离性级别:
首先,消除读取为提交隔离性级别。在不同的事务中使用一个为提交的事务变化是很危险的。一个事务的回滚或者失败将影响其他的并发事务。
甚至由一个终止回滚的事务所做的改变也可能在任何地方被提交,因为他们可能读取,然后由另一个成功的事务传播!
其次,大多数应用程序不需要可序列化的隔离级别(幻读通常不成问题),并且这个隔离性往往难以伸缩。
这样就把选择读取提交还是可重复读取交给你了。
Hibernate配置选项:
hibernate.connection.isolation = 4
1-读取为提交隔离性
2-读取提交隔离性
3-可重复读取隔离性
4-可序列化隔离性
乐观并发控制:
乐观的方法始终假设一切都会很好,并且很少有冲突的数据修改。在编写数据时,乐观并发控制值在工作单元结束时才出现错误。多用户
的应用程序通常默认为使用读取提交隔离性级别的乐观并发控制和数据库连接。只有适当的时候才获得额外的隔离性保证;这种方法保证
了最佳的性能和可伸缩性。
对于如何处理对话中这些第二个事务中的丢失更新,你有3种选择:
最晚提交生效(last commit wins)--两个事物提交都成功,第二个提交覆盖第一个变化。没有显示错误消息。
最早提交生效(fist commit wins)--对话A的事务被提交,并且在对话B中提交事务的用户得到一条错误信息。用户必须获取新数据来
重启会话,并在此利用没有失效的数据完成对话的所有步骤。
合并冲突更新(merge conflicting updates)--第一个修改被提交,并且对话B中的事务在提交时终止,带有一条错误消息。但是失败
的对话B用户可以选择性的应用变化,而不是再次在对话中完成所有工作。
在hibernate中启用版本控制:
hibernate提供自动的版本控制。每个实体实例都有一个版本,它可以是一个数字或者是一个时间戳。当对象修改时,hibernate就增加
他的版本号,自动比较版本,如果侦测到冲突就抛出异常。因此,你给所有持久化的实体类都添加这个版本属性,来启动乐观锁:
version:
配置:
代码:
timestamp(理论上讲,时间戳更不安全。且在集群环境中更不安全):
配置:
代码:
hibernate检查机制:
org.hibernate.persister.entity.AbstractEntityPersister.check:
org.hibernate.jdbc.Expectation:
版本控制的自动管理:
涉及目前被版本控制的Item对象的每一个DML操作都包括版本检查。例如,假设在一个工作单元中,你从版本为1的数据库中加载一个Item。然后修改它的其中一个值类型属性。当持久化
上下文被清除时,hibernate侦测到修改,并把Item的版本增加到2。然后执行SQL UPDATE使这一修改在数据库中永久化:
update item set intial_price = '11.23',obj_version=2 where item_id = 123 and obj_version=1
如果另一个并发的工作单元更新和提交了同一个行,obj_version列就不包含值1,行也不会被更新。hibernate检查由jdbc驱动器返回这个语句所更新
的行数---在这个例子中,被更新的行数为0--并抛出StaleObjectStateException。加载Item时呈现的状态,清除时不再在数据库中呈现;
因而,你真正使用失效的数据,必须通知应用程序的用户。可以捕捉这个异常,并显示一条错误消息,或者显示帮助用户给应用程序重启会话
的一个提示框。
如果你想要禁用对特定值类型属性或者集合的自动增加,就用optimistic-lock="false"属性映射他。
没有版本号或者时间戳的版本控制(如果你用的遗留表,不方便再添加字段):
用Java Persistence版本控制:
version:
实体:
更新:
报错:
Caused by: javax.persistence.OptimisticLockException
optimisticLock:
实体:
调用:
获得额外的隔离性保证:
1、显示的悲观锁
当我们关注应用程序的课伸缩性时。例如,对标量查询可能需要可重复读取。
不是把所有的数据库事务转换为一个更高的、不可伸缩的隔离性级别,而是在必要时,在Hibernate Session中使用lock()方法获得
更高的隔离性:
Java Persistence 的hibernate也实现了这个技术,但是规范并没有要求实现这个。
hibernate锁模式:
LockMode.NONE--别到数据库中去,除非对象不处于任何高速缓存中。
LockMode.READ--绕过所有高速缓存,并执行版本检查,来验证内存中的对象是否与当前数据中村中的版本相同。
LockMode.UPGRADE--绕过所有高速缓存,做一个版本检查,如果支持的话,就获得数据库级的悲观升级锁。相当于Java Persistence中的LockModeType.READ。如果数据库方言不支持
select...for update选项,这个模式就透明的退回到LockMode.READ。
LockMode.UPGRADE_NOWAIT--与LockMode.UPGRADE相同,但如果支持的话,就使用select...for update nowait。他禁用了等待并发所释放,因为如果无法获得锁,就立即抛出锁异常。
如果数据库SQL方言不支持nowait选择,这个模式就透明的退回到LockMode.UPGRADE。
LockMode.FORCE--在数据库中强制增加对象的版本,来表明他已经被当前事务修改。相当于Java Persistence中的LockModeType.WRITE。
LockMode.WRITE--当hibernate已经在当前事务中写到一个行时,就自动获得他。(内部模式)
默认情况下load()和get()使用NONE。
◆未授权读取(Read Uncommitted):允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个数据则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
◆授权读取(Read Committed):允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
◆可重复读取(Repeatable Read):禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
◆序列化(Serializable):提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
如果一个事务读取由另一个还没有被提交的事务进行的改变,就发生脏读取(dirty read)。这很危险,因为由其他事务进行的改变随后
可能回滚,并且低一个事务可能编写无效的数据。
如果一个事物读取一个行两次,并且每次读取不同的状态,就会发生不可重复读取(unrepeatable read)。例如,另一个事务可能已经
写到这个行,并已经在两次读取之间提交。
不可重复读取的一个特殊案例是二次丢失更新问题(second lost updates problem)。想象两个并发事务都读取一个行:一个写到行并
提交,然后第二个也写到行并提交。有第一个事务所做的改变丢失了。
幻读(phantom read)发生在一个事务执行一个查询两次,并且第二个结果集包括第一个结果集中不可见的行,或者包括已经删除的行时。
这种情况是由另一个事务在两次查询执行之间插入或者删除行照成的。
ANSI事务隔离性级别:
允许脏读取但不允许丢失更新的系统,要在读取未提交(read uncommitted)的隔离性中操作。如果一个为提交事务已经写到一个行,
另一个事务就不可能再写到这个行。但任何事务都可以读取任何行。这个隔离性级别可以在数据库管理系统中通过专门的写锁来实现。
允许不可重复读取但不允许脏读取系统,要实现读取提交(read committed)的事务隔离性。这可以用共享的读锁和专门的写锁来实现。
读取事务不会阻塞其他事务访问行。但是为提交的鞋事务隔赛所有其他的事务访问改行。
在可重复读(repeatable read)隔离性模式中操作的系统既不允许不可重复读取,也不允许脏读取。幻读可能发生。
可序列化 (serializable)提供最严格的事务隔离性。这个隔离性级别模拟连续的事务执行,好像事务是连续的一个接一个的执行,而不是
并发的执行。
选择隔离性级别:
首先,消除读取为提交隔离性级别。在不同的事务中使用一个为提交的事务变化是很危险的。一个事务的回滚或者失败将影响其他的并发事务。
甚至由一个终止回滚的事务所做的改变也可能在任何地方被提交,因为他们可能读取,然后由另一个成功的事务传播!
其次,大多数应用程序不需要可序列化的隔离级别(幻读通常不成问题),并且这个隔离性往往难以伸缩。
这样就把选择读取提交还是可重复读取交给你了。
Hibernate配置选项:
hibernate.connection.isolation = 4
1-读取为提交隔离性
2-读取提交隔离性
3-可重复读取隔离性
4-可序列化隔离性
乐观并发控制:
乐观的方法始终假设一切都会很好,并且很少有冲突的数据修改。在编写数据时,乐观并发控制值在工作单元结束时才出现错误。多用户
的应用程序通常默认为使用读取提交隔离性级别的乐观并发控制和数据库连接。只有适当的时候才获得额外的隔离性保证;这种方法保证
了最佳的性能和可伸缩性。
对于如何处理对话中这些第二个事务中的丢失更新,你有3种选择:
最晚提交生效(last commit wins)--两个事物提交都成功,第二个提交覆盖第一个变化。没有显示错误消息。
最早提交生效(fist commit wins)--对话A的事务被提交,并且在对话B中提交事务的用户得到一条错误信息。用户必须获取新数据来
重启会话,并在此利用没有失效的数据完成对话的所有步骤。
合并冲突更新(merge conflicting updates)--第一个修改被提交,并且对话B中的事务在提交时终止,带有一条错误消息。但是失败
的对话B用户可以选择性的应用变化,而不是再次在对话中完成所有工作。
在hibernate中启用版本控制:
hibernate提供自动的版本控制。每个实体实例都有一个版本,它可以是一个数字或者是一个时间戳。当对象修改时,hibernate就增加
他的版本号,自动比较版本,如果侦测到冲突就抛出异常。因此,你给所有持久化的实体类都添加这个版本属性,来启动乐观锁:
version:
- publicclassItemimplementsSerializable {
- privateInteger itemId;
- privateString itemName;
- /** 版本控制 */
- privateintversion;
配置:
- <classname="Item"table="ITEM">
- <id name="itemId"column="ITEM_ID"type="integer">
- <generatorclass="native"/>
- </id>
- <!-- XML格式的version属性映射必须立即放在标示符属性映射之后 -->
- <version name="version"access="field"column="OBJ_VERSION"/>
- <property name="itemName"type="string"column="ITEM_NAME"/>
- </class>
代码:
- /**
- * 报错:
- * org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
- * @param itemName
- */
- privatestaticvoidupdate1(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- //一样会报错
- //item1.setItemName(itemName);
- item1.setItemName(itemName+"1");
- tr.commit();
- session.close();
- //org.hibernate.StaleObjectStateException:
- //Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
- tr1.commit();
- session1.close();
- sessionFactory.close();
- }
- /**
- * 提交成功
- * @param itemName
- */
- privatestaticvoidupdate2(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- tr.commit();
- session.close();
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- item1.setItemName(itemName+"1");
- tr1.commit();
- session1.close();
- sessionFactory.close();
- }
timestamp(理论上讲,时间戳更不安全。且在集群环境中更不安全):
- publicclassItemimplementsSerializable {
- privateInteger itemId;
- privateString itemName;
- /** 版本控制 */
- privateDate lastUpdated;
配置:
- <classname="Item"table="ITEM">
- <id name="itemId"column="ITEM_ID"type="integer">
- <generatorclass="native"/>
- </id>
- <timestamp name="lastUpdated"access="field"column="LAST_UPDATED"></timestamp>
- <property name="itemName"type="string"column="ITEM_NAME"/>
- </class>
代码:
- /**
- * 报错:
- * org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
- * @param itemName
- */
- privatestaticvoidupdate1(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- //一样会报错
- //item1.setItemName(itemName);
- item1.setItemName(itemName+"1");
- tr.commit();
- session.close();
- //org.hibernate.StaleObjectStateException:
- //Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
- tr1.commit();
- session1.close();
- sessionFactory.close();
- }
- /**
- * 提交成功
- * @param itemName
- */
- privatestaticvoidupdate2(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- tr.commit();
- session.close();
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- item1.setItemName(itemName+"1");
- tr1.commit();
- session1.close();
- sessionFactory.close();
- }
hibernate检查机制:
org.hibernate.persister.entity.AbstractEntityPersister.check:
- protectedbooleancheck(introws, Serializable id,inttableNumber, Expectation expectation, PreparedStatement statement)throwsHibernateException {
- try{
- expectation.verifyOutcome( rows, statement, -1);
- }
- catch( StaleStateException e ) {
- if( !isNullableTable( tableNumber ) ) {
- if( getFactory().getStatistics().isStatisticsEnabled() ) {
- getFactory().getStatisticsImplementor()
- .optimisticFailure( getEntityName() );
- }
- thrownewStaleObjectStateException( getEntityName(), id );
- }
- returnfalse;
- }
- catch( TooManyRowsAffectedException e ) {
- thrownewHibernateException(
- "Duplicate identifier in table for: "+
- MessageHelper.infoString(this, id, getFactory() )
- );
- }
- catch( Throwable t ) {
- returnfalse;
- }
- returntrue;
- }
org.hibernate.jdbc.Expectation:
- /**
- * Perform verification of the outcome of the RDBMS operation based on
- * the type of expectation defined.
- *
- * @param rowCount The RDBMS reported "number of rows affected".
- * @param statement The statement representing the operation
- * @param batchPosition The position in the batch (if batching)
- * @throws SQLException Exception from the JDBC driver
- * @throws HibernateException Problem processing the outcome.
- */
- publicvoidverifyOutcome(introwCount, PreparedStatement statement,intbatchPosition)throwsSQLException, HibernateException;
- /**
- * 我用了两个factory,也是可以提交成功的
- * 你想想,这证明了什么
- * @param itemName
- */
- privatestaticvoidupdate3(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- tr.commit();
- session.close();
- sessionFactory.close();
- Configuration configuration1 =newConfiguration().configure();
- SessionFactory sessionFactory1 = configuration1.buildSessionFactory();
- Session session1 = sessionFactory1.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- item1.setItemName(itemName+"11");
- tr1.commit();
- session1.close();
- sessionFactory1.close();
- }
版本控制的自动管理:
涉及目前被版本控制的Item对象的每一个DML操作都包括版本检查。例如,假设在一个工作单元中,你从版本为1的数据库中加载一个Item。然后修改它的其中一个值类型属性。当持久化
上下文被清除时,hibernate侦测到修改,并把Item的版本增加到2。然后执行SQL UPDATE使这一修改在数据库中永久化:
update item set intial_price = '11.23',obj_version=2 where item_id = 123 and obj_version=1
如果另一个并发的工作单元更新和提交了同一个行,obj_version列就不包含值1,行也不会被更新。hibernate检查由jdbc驱动器返回这个语句所更新
的行数---在这个例子中,被更新的行数为0--并抛出StaleObjectStateException。加载Item时呈现的状态,清除时不再在数据库中呈现;
因而,你真正使用失效的数据,必须通知应用程序的用户。可以捕捉这个异常,并显示一条错误消息,或者显示帮助用户给应用程序重启会话
的一个提示框。
如果你想要禁用对特定值类型属性或者集合的自动增加,就用optimistic-lock="false"属性映射他。
没有版本号或者时间戳的版本控制(如果你用的遗留表,不方便再添加字段):
- <!-- org.hibernate.MappingException: optimistic-lock=all|dirty requires dynamic-update="true"-->
- <!-- dirty的区别在于,只有当某个属性共同修改时,才报错;all是只要有修改就报错 -->
- <classname="Item"table="ITEM"optimistic-lock="all"dynamic-update="true">
- <id name="itemId"column="ITEM_ID"type="integer">
- <generatorclass="native"/>
- </id>
- <property name="itemName"type="string"column="ITEM_NAME"/>
- </class>
用Java Persistence版本控制:
version:
实体:
- @Entity
- publicclassItemimplementsSerializable {
- @Id
- @GeneratedValue
- @Column(name="ITEM_ID")
- privateInteger itemId;
- @Column(name="ITEM_NAME")
- privateString itemName;
- /** 版本控制 */
- @Version
- @Column(name="OBJ_VERSION")
- privateintversion;
更新:
- privatestaticvoidupdate(String itemName) {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- EntityTransaction tr = em.getTransaction();
- tr.begin();
- Item item = em.find(Item.class,1);
- item.setItemName(itemName);
- EntityManager em1 = factory.createEntityManager();
- EntityTransaction tr1 = em1.getTransaction();
- tr1.begin();
- Item item1 = em1.find(Item.class,1);
- item1.setItemName(itemName+"he");
- tr.commit();
- em.close();
- //Caused by: javax.persistence.OptimisticLockException
- tr1.commit();
- em1.close();
- factory.close();
- }
报错:
Caused by: javax.persistence.OptimisticLockException
optimisticLock:
实体:
- @Entity
- //optimistic-lock=all|dirty requires dynamic-update="true"
- @org.hibernate.annotations.Entity(
- optimisticLock=OptimisticLockType.ALL,
- dynamicUpdate=true)
- publicclassItemimplementsSerializable {
- @Id
- @GeneratedValue
- @Column(name="ITEM_ID")
- privateInteger itemId;
- @Column(name="ITEM_NAME")
- privateString itemName;
- //版本检测排除下面的属性
- @OptimisticLock(excluded=true)
- privateDouble price;
- publicItem() {
- super();
- }
调用:
- /**
- * 报错
- * Caused by: javax.persistence.OptimisticLockException
- * @param itemName
- */
- privatestaticvoidupdate1(String itemName) {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- EntityTransaction tr = em.getTransaction();
- tr.begin();
- Item item = em.find(Item.class,1);
- item.setItemName(itemName);
- EntityManager em1 = factory.createEntityManager();
- EntityTransaction tr1 = em1.getTransaction();
- tr1.begin();
- Item item1 = em1.find(Item.class,1);
- item1.setItemName(itemName+"he");
- tr.commit();
- em.close();
- //Caused by: javax.persistence.OptimisticLockException
- tr1.commit();
- em1.close();
- factory.close();
- }
- /**
- * 不会报错
- * @param price
- */
- privatestaticvoidupdate2(Double price) {
- EntityManagerFactory factory = Persistence.createEntityManagerFactory("partner4java");
- EntityManager em = factory.createEntityManager();
- EntityTransaction tr = em.getTransaction();
- tr.begin();
- Item item = em.find(Item.class,1);
- item.setPrice(price);
- EntityManager em1 = factory.createEntityManager();
- EntityTransaction tr1 = em1.getTransaction();
- tr1.begin();
- Item item1 = em1.find(Item.class,1);
- item1.setPrice(price+1D);
- tr.commit();
- em.close();
- tr1.commit();
- em1.close();
- factory.close();
- }
获得额外的隔离性保证:
1、显示的悲观锁
当我们关注应用程序的课伸缩性时。例如,对标量查询可能需要可重复读取。
不是把所有的数据库事务转换为一个更高的、不可伸缩的隔离性级别,而是在必要时,在Hibernate Session中使用lock()方法获得
更高的隔离性:
- /**
- * session.lock(item, LockMode.UPGRADE);
- * @param itemName
- */
- privatestaticvoidupdate1(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- //指定锁级别
- session.lock(item, LockMode.UPGRADE);
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,1);
- item1.setItemName(itemName+"1");
- //停在这步,因为碰到for update的锁了,他要等到tr提交了之后才会执行,但是,我们这个demo当然无法执行到这步
- tr1.commit();
- session1.close();
- tr.commit();
- session.close();
- sessionFactory.close();
- }
- /**
- * 只锁定指定列的数据,不会锁定表
- * 但是,以前这种方式是悲观锁,会锁定整个表,如果指定锁定某一行,如下:
- * Item item = (Item) session.get(Item.class, 1, LockMode.UPGRADE);
- * @param itemName
- */
- privatestaticvoidupdate2(String itemName) {
- Configuration configuration =newConfiguration().configure();
- SessionFactory sessionFactory = configuration.buildSessionFactory();
- Session session = sessionFactory.openSession();
- Transaction tr = session.beginTransaction();
- Item item = (Item) session.get(Item.class,1);
- item.setItemName(itemName);
- //指定锁级别
- session.lock(item, LockMode.UPGRADE);
- Session session1 = sessionFactory.openSession();
- Transaction tr1 = session1.beginTransaction();
- Item item1 = (Item) session1.get(Item.class,2);
- item1.setItemName(itemName+"1");
- //执行通过
- tr1.commit();
- session1.close();
- tr.commit();
- session.close();
- sessionFactory.close();
- }
Java Persistence 的hibernate也实现了这个技术,但是规范并没有要求实现这个。
hibernate锁模式:
LockMode.NONE--别到数据库中去,除非对象不处于任何高速缓存中。
LockMode.READ--绕过所有高速缓存,并执行版本检查,来验证内存中的对象是否与当前数据中村中的版本相同。
LockMode.UPGRADE--绕过所有高速缓存,做一个版本检查,如果支持的话,就获得数据库级的悲观升级锁。相当于Java Persistence中的LockModeType.READ。如果数据库方言不支持
select...for update选项,这个模式就透明的退回到LockMode.READ。
LockMode.UPGRADE_NOWAIT--与LockMode.UPGRADE相同,但如果支持的话,就使用select...for update nowait。他禁用了等待并发所释放,因为如果无法获得锁,就立即抛出锁异常。
如果数据库SQL方言不支持nowait选择,这个模式就透明的退回到LockMode.UPGRADE。
LockMode.FORCE--在数据库中强制增加对象的版本,来表明他已经被当前事务修改。相当于Java Persistence中的LockModeType.WRITE。
LockMode.WRITE--当hibernate已经在当前事务中写到一个行时,就自动获得他。(内部模式)
默认情况下load()和get()使用NONE。
相关推荐
至于并发控制,主要目的是解决多用户同时访问同一数据时可能出现的问题,如脏读、不可重复读和幻读等。在数据库层面,常见的并发控制机制包括锁和乐观锁。Hibernate提供了多种并发策略,如版本字段(version)和...
本文将深入探讨Hibernate中的事务和并发控制,这对于开发高效、稳定的数据库应用至关重要。 首先,我们来理解Hibernate中的事务管理。在数据库操作中,事务是保证数据一致性的重要手段。一个事务包含了一组数据库...
在Hibernate中,事务、并发控制和缓存管理是至关重要的概念,它们极大地影响了应用程序的性能和数据一致性。 一、Hibernate事务管理 在数据库操作中,事务确保了数据的一致性和完整性。Hibernate提供了四种事务隔离...
总之,Hibernate的版本管理机制是解决事务并发问题的有效手段,通过合理地利用乐观锁和悲观锁,开发者可以创建出高效且一致性的数据访问层。在开发过程中,理解并掌握这些并发控制策略对于优化系统的性能和稳定性至...
在多用户同时访问数据库时,事务并发控制就显得尤为重要,以防数据冲突和不一致。 悲观锁是假设最坏的情况,即每次读取数据时都假设会有其他用户同时尝试修改。因此,悲观锁会在数据读取时立即加上锁,直到事务结束...
以下是关于Hibernate事务和并发控制的详细讨论。 1. **数据库事务的定义** 数据库事务是一系列操作的逻辑单位,这些操作要么全部成功,要么全部失败。事务满足ACID属性: - **原子性**(Atomicity):事务中的...
《课程hibernate的事务和并发》主要探讨了在Hibernate框架中如何管理和处理事务以及并发控制。Hibernate作为一款流行的Java ORM(对象关系映射)工具,其事务处理和并发控制策略对于开发高效、稳定的数据库应用至关...
《Hibernate的事务和并发资料》深入探讨了在Java应用程序中使用Hibernate进行事务管理和并发控制的关键概念。Hibernate作为一款流行的ORM框架,它简化了与数据库的交互,但同时也需要开发者理解其背后的事务处理机制...
数据版本并发性控制可以使用版本、时间戳等方式来控制并发访问。 集合映射 Hibernate 的集合映射可以将一个对象的集合属性映射到数据库中。集合映射可以是 set、list、map、bag、array 等。级联策略控制可以控制...
同时,还会讨论事务管理和并发控制,确保数据的一致性和完整性。 查询语言在Hibernate中主要有两种:HQL(Hibernate Query Language)和 Criteria API。HQL是面向对象的查询语言,类似于SQL,但更接近于Java的语法...
在Spring框架中,为了管理和控制Hibernate事务,Spring提供了两种关键工具:HibernateTemplate和JdbcTemplate。这两个模板类简化了与数据库的交互,同时也处理了事务管理。让我们深入了解一下这两个类以及它们如何...
二级缓存可以通过设置不同的并发访问策略来解决并发问题,如事务型、读写型或非严格读写型,以适应不同场景下的需求。 持久化层的缓存范围决定了缓存的生命周期和访问权限。事务范围的缓存最安全,但只限于当前事务...
事务并发访问控制分为两类:同一系统事务内的并发控制和跨系统事务的并发控制。在讨论具体策略之前,首先需要理解数据库事务的四种隔离级别。 1. 读取未提交(Read Uncommitted):这是最低的隔离级别,允许脏读,...
Hibernate支持乐观锁和悲观锁机制,处理多用户并发访问同一数据时可能出现的问题。乐观锁假设并发冲突较少,而在数据更新时检查版本号;悲观锁则在读取数据时就加锁,防止其他用户修改。 五、缓存与性能优化 1. 第...
8. **实际应用**:这种配置适用于高并发、读多写少的Web应用,例如电子商务网站的商品详情页,通过缓存减少对数据库的频繁访问,提高响应速度。 综上所述,这个项目展示了如何在Java环境下,利用Maven构建工具,将...
2. **事务管理**:在新版本的方言中,对事务的处理进行了优化,支持更灵活的事务隔离级别,提高了并发控制的效率和数据的一致性。 3. **索引和约束**:方言更新可能涉及到对索引和表约束的处理,确保了在创建和管理...
本文将深入探讨 Hibernate 的缓存机制,包括其两个级别——一级缓存和二级缓存,并讨论它们的工作原理、范围、并发访问策略以及如何管理和配置。 1. **一级缓存** - **范围与作用**:一级缓存是 Session 级别的...
20. **实体的版本控制(Versioning)**:通过乐观锁或悲观锁实现并发控制,防止数据冲突。 通过深入阅读《Hibernate官方参考手册》,开发者可以全面掌握Hibernate的使用方法,从而高效地开发Java应用程序的数据访问...
C3P0是常用的数据库连接池实现,它可以管理数据库连接的生命周期,提供并发访问的高效性。`min_size`值决定了当连接池空闲时,最少保持的连接数量,以应对可能的并发请求。 这四个属性是Hibernate配置的核心部分,...
这可以显著减少对数据库的访问次数,尤其在高并发场景下。 8. **懒加载和立即加载**: Hibernate 提供了懒加载和立即加载机制来控制关联对象的加载时机。懒加载只在真正需要时才加载关联对象,而立即加载则会在...