高级特性—数据库锁操作
数据库是一个多用户使用的共享资源,当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况,若对并发操作不加以控制就可能会造成数据的错误读取和存储,破坏数据库的数据一致性,所以说,加锁是实现数据库并发控制的一个非常重要的技术;
数据库加锁的流程是:当事务在对某个数据对象进行操作前,先向系统发出请求对其加锁,加锁后的事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作;
因此,JDBC模块在数据库查询操作中集成了针对数据库记录锁的控制能力,称之为IDBLocker,以参数的方式使用起来同样的简单!
首先了解一下IDBLocker提供的锁的类型:
-
Mysql:
IDBLocker.mysql:行级锁,只有符合条件的数据被加锁,其它进程等待资源解锁后再进行操作;
-
oracle:
IDBLocker.ORACLE:行级锁,只有符合条件的数据被加锁,其它进程等待资源解锁后再进行操作;
IDBLocker.ORACLE_NOWAIT:行级锁,不进行资源等待,只要发现结果集中有些数据被加锁,立刻返回“ORA-00054错误”;
-
SQL Server:
IDBLocker.SQLSERVER_NOLOCK:不加锁,在读取或修改数据时不加任何锁;
IDBLocker.SQLSERVER_HOLDLOCK:保持锁,将此共享锁保持至整个事务结束,而不会在途中释放;
IDBLocker.SQLSERVER_UPDLOCK:修改锁,能够保证多个进程能同时读取数据但只有该进程能修改数据;
IDBLocker.SQLSERVER_TABLOCK:表锁,整个表设置共享锁直至该命令结束,保证其他进程只能读取而不能修改数据;
IDBLocker.SQLSERVER_PAGLOCK:页锁;
IDBLocker.SQLSERVER_TABLOCKX:排它表锁,将在整个表设置排它锁,能够防止其他进程读取或修改表中的数据;
-
其它数据库:
可以通过IDBLocker接口自行实现;
下面通过示例代码展示如何使用锁:
示例代码一:通过EntitySQL对象传递锁参数;
session.find(EntitySQL.create(User.class) .field(Fields.create(User.FIELDS.ID, User.FIELDS.USER_NAME).excluded(true)) .forUpdate(IDBLocker.MYSQL));
示例代码二:通过Select查询对象传递锁参数;
Select _select = Select.create(User.class, "u") .field("u", "username").field("ue", "money") .where(Where.create( Cond.create().eq(User.FIELDS.ID).param("bc19f5645aa9438089c5e9954e5f1ac5"))) .forUpdate(IDBLocker.MYSQL); session.find(SQL.create(_select), IResultSetHandler.ARRAY);
示例代码三:基于数据实体对象传递锁参数
// User _user = new User(); _user.setId("bc19f5645aa9438089c5e9954e5f1ac5"); // _user.load(IDBLocker.MYSQL); // User _user = new User(); _user.setUsername("suninformation"); _user.setPwd(DigestUtils.md5Hex("123456")); // IResultSet<User> _users = _user.find(IDBLocker.MYSQL);
注意:
请谨慎使用数据库锁机制,尽量避免产生锁表,以免发生死锁情况!