• Hibernate 配置详解(7)


    hibernate.order_updates:

    Hibernate文档中提到,该配置用于在刷新一级缓存,提交UPDATE的时候,按照每类对象的主键顺序排序后再提交,可以在高并发情况下减少事务死锁的可能。这个配置默认为false,但是非常建议在可能存在高并发情况下开启,因为其实按照类型ID排序(在内存中),并不会消耗过多性能。那么这个配置到底什么含义呢?做个简单的测试。

    首先准备一个对象User,完成映射(略),完成下面的测试:

      @Before
      	public void save(){
      		Session session=sf.openSession();
      		session.beginTransaction();
      		for(int i=0;i<10;i++){
      			User u=new User();
      			u.setName(Math.random()+"");
      			session.save(u);
      		}
      		session.getTransaction().commit();
      		session.close();
      	}

    首先任意的保存10个对象,然后模拟高并发修改:

      @Test
      	public void testUpdate() throws Exception{
      		for(int i=0;i<10;i++){
      			Thread t=new Thread(new Runnable() {
      				Random random=new Random();
      				public void run() {
      					Session session=sf.openSession();
      					session.beginTransaction();
      					for(int i=0;i<5;i++){
      						Long id= new Long(random.nextInt(10)+1);
      						System.out.println(Thread.currentThread().getName()+"    "+id);
      						User u=(User)session.get(User.class,id);
      						u.setName(Math.random()+"");
      					}
      					session.getTransaction().commit();
      					session.close();
      				}
      			},"thread"+i);
      			t.start();
      		}
      		Thread.sleep(10000);
      	}

    该测试开启10个线程,在每个线程中的同一个事务中,随机得到5个User对象,并修改名字,然后提交事务。运行测试,99%的情况下都会报错:

      Caused by: com.mysql.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
      	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:941)
      	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2941)
      	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1623)
      	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1715)
      	at com.mysql.jdbc.Connection.execSQL(Connection.java:3249)
      	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1268)
      	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1541)
      	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1455)
      	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1440)
      	at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:133)
    	... 16 more

    造成了死锁,异常产生原因简单分析如下:

    假设Thread1得到的User对象的顺序为1,4,6,9,3;Thread2得到的User对象的顺序为2,3,9,8,4;那么假设当Thread1运行到update4的时候,锁住ID:4这行数据,Thread2运行到update9,锁住ID:9这行数据,Thread1运行到update 9的时候等待Thread2释放ID:9这行数据的锁,Thread2运行到update 4的时候,等待Thread1释放ID:4这行数据的锁,造成死锁。

    如果修改hibernate配置文件:

      <property name="hibernate.order_updates">true</property>

    再次运行,运行测试成功。

    在update的时候,ID排序了。执行过程简单分析如下:

    Thread1得到User对象的顺序为1,4,6,9,3;但是在更新的时候顺序调整为1,3,4,6,9;

    Thread2得到User对象的顺序为2,3,9,8,4;但是在更新的时候顺序调整为2,3,4,9,8;

    那么当Thread2更新ID:3的时候,就会等着Thread1释放锁,而不会锁住任何ID:3之前的数据,所以不会造成Thread1的死锁,所以能正常运行。(MySQL总是一条一条执行SQL)。

    个人认为这个选项建议设置为true。


  • 相关阅读:
    Admin注册和路由分发详解
    自定义Xadmin
    苑昊老师的博客
    pip 国内源 配置
    Django模型层(2)
    Django 中间件
    Django form表单
    整理的最全 python常见面试题(基本必考)
    AJAX
    Cookie、Session和自定义分页
  • 原文地址:https://www.cnblogs.com/riskyer/p/3281450.html
Copyright © 2020-2023  润新知