java 使用休眠锁定表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30323459/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Locking a table with hibernate
提问by user2162550
I have a Client-Server app, and in my server I'm using hibernate for database handling. Now, my app requires among all the database tables, a simple table with only one row of one Biginteger
field (which is the key in this row) in it. This table will actually contain only a global number (starting from 1) which I use every time a user performing some action, and when he does, I need to get this value, and increment the value in the database. (the table shoud contain only one row with only one value all the time)
我有一个客户端-服务器应用程序,在我的服务器中我使用 hibernate 进行数据库处理。现在,我的应用程序需要在所有数据库表中,一个简单的表,其中只有一行一个Biginteger
字段(这是该行中的键)。这个表实际上只包含一个全局数字(从 1 开始),我每次用户执行某些操作时都会使用它,当他这样做时,我需要获取这个值,并增加数据库中的值。(该表应该只包含一行,并且始终只有一个值)
I'm using the following code to accomplish that:
我正在使用以下代码来完成它:
Biginteger func() {
Session s = null;
Biginteger idToReturn=null;
try{
s=factory.openSession();
s.beginTransaction();
Query queryResult = s.createQuery("from GlobalId");
List<GlobalID> theId=queryResult.list();
idToReturn=theId.get(0).get_id(); //getting the value from db to return
GlobalID toSave=new GlobalId();
toSave.set_id(idToReturn.add(BigInteger.valueOf(1))); //incrementing the id from db inorder to save it
s.delete(theId.get(0)); //deleting old id
s.save(toSave); //saving new id
s.getTransaction().commit();
}
catch(Exception e){
throw e;
}
finally{
if (s!=null)
s.close();
return idToReturn;
}
}
This code works fine. My concern is about if I'll need to use more than one server to approach a central database. In that case, if two seperate servers will run this function, I need to eliminate the case that the two of them will get the same value. I need to make sure the entire read and write will be "atomic", I need to lock this table so no more than one session will be able to read the value, and I also need to make sure in case the session ended unexpectedly, the lock will be removed.
这段代码工作正常。我担心的是我是否需要使用多个服务器来访问中央数据库。在这种情况下,如果两个单独的服务器将运行此功能,我需要消除它们两个将获得相同值的情况。我需要确保整个读写都是“原子的”,我需要锁定这个表,这样只有一个会话才能读取该值,我还需要确保会话意外结束,锁将被移除。
I'm using the xampp bundle including MySQL 5.6 database.
我正在使用包含 MySQL 5.6 数据库的 xampp 包。
The informationI found online regarding this issue is confusing to me- the information I found is "high level" and I could not find any examples.
我在网上找到的关于这个问题的信息让我感到困惑——我找到的信息是“高级”的,我找不到任何例子。
采纳答案by rghome
You need to use pessimistic locking, which can be achieved by
您需要使用悲观锁定,这可以通过
setLockMode(String alias, LockMode lockMode)
on the query and use LockMode.UPGRADE
.
关于查询和使用LockMode.UPGRADE
。
However, this will certainly kill scalability and performance if you are doing a lot of access on this table. You are better either using a sequence or another strategy is to create a service to allocate numbers (e.g., an SSB) which grabs 100 numbers at a time, updates the database, and hands them out. That saves you 198 database accesses.
但是,如果您对该表进行大量访问,这肯定会扼杀可扩展性和性能。您最好使用序列或另一种策略是创建一个服务来分配号码(例如,SSB),该服务一次抓取 100 个号码,更新数据库,然后将它们分发出去。这为您节省了 198 次数据库访问。
UPDATE:
更新:
You will also have to modify your table design slightly. It is better to have a single row with a known ID and to store the number you are incrementing in another column. Then you should update the row rather than deleting the old row and adding a new one. Otherwise, the row locking strategy won't work.
您还必须稍微修改您的表格设计。最好有一个具有已知 ID 的单行,并将您要增加的数字存储在另一列中。然后您应该更新该行而不是删除旧行并添加新行。否则,行锁定策略将不起作用。
UPDATE2:
更新2:
OP found that the following worked:
OP发现以下方法有效:
session.get(class.Class, id, lockOption)