java:Hibernate框架4(延迟加载(lazy),抓取(fetch),一级缓存,get,load,list,iterate,clear,evict,flush,二级缓存,注解,乐观锁和悲观锁,两者的比较)
1.延时加载和抓取:
hibernate.cfg.xml:
<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <!-- Generated by MyEclipse Hibernate Tools. --> <hibernate-configuration> <session-factory> <property name="myeclipse.connection.profile">udisk</property> <property name="connection.url"> jdbc:mysql://localhost:3306/udisk </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="show_sql">true</property> <property name="format_sql">true</property> <mapping resource="cn/zzsxt/entity/Fileinfo.hbm.xml" /> <mapping resource="cn/zzsxt/entity/Userinfo.hbm.xml" /> </session-factory> </hibernate-configuration>
TestFetch:
package cn.zzsxt.demo3; import java.util.Iterator; import org.hibernate.Query; import org.hibernate.Session; import cn.zzsxt.entity.Fileinfo; import cn.zzsxt.entity.Userinfo; import cn.zzsxt.util.HibernateSessionFactory; /** * 抓取策略:select/join * select 抓取:表示查询关联对象时,使用select语句。(在select抓取下,可以用lazy) * Join抓取:查询关联对象时,使用join 连接语句。Lazy没有意义(没有作用)。 * N+1问题解决方案: * 1.使用lazy="true"延迟加载的方式 * 2.使用hibernate中缓存策略 * 3.使用join的抓取策略 * list()/iterator() */ public class TestFetch { public static void testSelectAndJoin(){ Session session = HibernateSessionFactory.getSession(); Fileinfo fileinfo = (Fileinfo)session.get(Fileinfo.class, 2); System.out.println(fileinfo.getFileId()+"--"+fileinfo.getFileName()); Userinfo user = fileinfo.getUserinfo(); System.out.println(user.getUserId()+"**"+user.getUserName()); HibernateSessionFactory.closeSession(); } /** *使用iterator方法查询时会先查询所有的id,然后根据id查询每一条记录,会产生典型 N+1问题 *可以使用list避免 */ public static void testIterator(){ Session session = HibernateSessionFactory.getSession(); Query query = session.createQuery("from Fileinfo"); // query.list() Iterator<Fileinfo> iterator = query.iterate(); while(iterator.hasNext()){ Fileinfo fileinfo = iterator.next(); System.out.println(fileinfo); } HibernateSessionFactory.closeSession(); } public static void main(String[] args) { // testSelectAndJoin(); testIterator(); } }
TestLazy:
package cn.zzsxt.demo3; import java.util.Set; import org.hibernate.Session; import cn.zzsxt.entity.Fileinfo; import cn.zzsxt.entity.Userinfo; import cn.zzsxt.util.HibernateSessionFactory; /** *get()/load()区别: * 1.get()采用的即时加载,如果查找不到将返回null * 2.load()采用延迟加载/真是使用到查询对象时才发送和执行SQL语句, * 如果查找不到将抛出org.hibernate.ObjectNotFoundException,查询返回的是一个代理对象 * 3.get()默认使用缓存,而load()则不会 */ public class TestLazy { public static void testGet(){ Session session= HibernateSessionFactory.getSession(); Userinfo user = (Userinfo)session.get(Userinfo.class, 30); // System.out.println(user); // System.out.println(user.getUserId()+"---"+user.getUserName()); HibernateSessionFactory.closeSession(); } public static void testLoad(){ Session session= HibernateSessionFactory.getSession(); Userinfo user = (Userinfo)session.load(Userinfo.class, new Integer(30)); System.out.println(user); // System.out.println(user.getUserId()+"---"+user.getUserName()); HibernateSessionFactory.closeSession(); } /** * lazy=false:即时加载,当查询对象时将与之关联的对象一并查出 */ public static void testLazy(){ Session session= HibernateSessionFactory.getSession(); Userinfo user = (Userinfo)session.get(Userinfo.class, 3); HibernateSessionFactory.closeSession(); System.out.println(user.getUserId()+"---"+user.getUserName()); Set<Fileinfo> set = user.getFileinfos(); for (Fileinfo fileinfo : set) { System.out.println(fileinfo.getFileId()+"---"+fileinfo.getFileName()); } // HibernateSessionFactory.closeSession(); } /** * lazy="true":延迟加载,将查询推迟到真正使用对象时才会发送和执行SQL语句, * 在查询的过程中必须保持session处于可用状态,否则将会抛出org.hibernate.LazyInitializationException * */ public static void testLazy2(){ Session session= HibernateSessionFactory.getSession(); Userinfo user = (Userinfo)session.get(Userinfo.class, 3); // HibernateSessionFactory.closeSession(); System.out.println(user.getUserId()+"---"+user.getUserName()); Set<Fileinfo> set = user.getFileinfos(); for (Fileinfo fileinfo : set) { System.out.println(fileinfo.getFileId()+"---"+fileinfo.getFileName()); } HibernateSessionFactory.closeSession(); } public static void main(String[] args) { // testGet(); // testLoad(); testLazy2(); } }
2.一级缓存和二级缓存:
一级缓存含义:
又称为session缓存,由session来管理,和session的生命周期相同,是事务级别的缓存(线程)。
二级缓存:
适合缓存的数据:
1.非关键性的数据;
2.数据大小在可接受范围内;
3.非频繁更新的数据;
4.访问频次较高的数据。
如何使用ehcache?
1.添加ehcache的jar文件(hibernate-release-5.2.10.Final\lib\optional\ehcache)
ehcache-2.10.3.jar
hibernate-ehcache-5.2.10.Final.jar
slf4j-api-1.7.7.jar
2.在src下新建ehcache.xml配置文件(ehcache的核心配置文件)
在hibernate-release-5.2.10.Final\project\etc下有个ehcache.xml的配置示例
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
maxElementsInMemory:缓存对象最大的个数
eternal:是否永久缓存
timeToIdleSeconds:最大的空闲间隔时间,单位为秒
timeToLiveSeconds:最大存活时间(生命周期),单位为秒
overflowToDisk:是否将溢出的对象写入硬盘
3.在hibernate.cfg.xml中配置二级缓存(默认为开启)
<!-- 配置二级缓存 -->
<!-- 开启二级缓存 默认为true -->
<property name="cache.use_second_level_cache">true</property>
<property name="cache.provider_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
4.在映射文件中(*.hbm.xml)配置缓存策略:
缓存策略:
read-only:只读
nonstrict-read-write:非严格读写
read-write:严格读写
<cache usage="read-only"/>
配置查询缓存:
1.在hibernate.cfg.xml中启用查询缓存
<!-- 配置查询缓存 -->
<property name="cache.use_query_cache">true</property>
2.在利用Query对象执行查询之前,调用query1.setCacheable(true)将查询的结果保存到二级缓存中,启用二级查询缓存。
ecache.xml:(src下,二级缓存)
<!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ License: GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. --> <ehcache> <!-- Sets the path to the directory where cache .data files are created. If the path is a Java System Property it is replaced by its value in the running VM. The following properties are translated: user.home - User's home directory user.dir - User's current working directory java.io.tmpdir - Default temp file path --> <diskStore path="java.io.tmpdir"/> <!--Default Cache configuration. These will applied to caches programmatically created through the CacheManager. The following attributes are required for defaultCache: maxInMemory - Sets the maximum number of objects that will be created in memory eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element is never expired. timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used if the element is not eternal. Idle time is now - last accessed time timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used if the element is not eternal. TTL is now - creation time overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache has reached the maxInMemory limit. --> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> </ehcache>
hibernate.cfg.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!--驱动名称,URL,用户名,密码 --> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="connection.url"> jdbc:mysql://localhost:3306/hibernate4 </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!--方言 --> <property name="hibernate.dialect"> org.hibernate.dialect.MySQL5Dialect </property> <!-- 输出SQL语句 --> <property name="show_sql">true</property> <!-- 格式化SQL语句 --> <property name="format_sql">true</property> <!-- 根据映射文件生产表: create:创建(不推荐:先删除原有表,重新创建表,原有数据丢失) update:创建+更新记录(推荐,会保存原有数据) --> <property name="hbm2ddl.auto">update</property> <!-- 启用二级缓存 --> <property name="cache.use_second_level_cache">true</property> <!-- 配置ehcache缓存提供类 --> <property name="cache.provider_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory </property> <property name="cache.region.factory_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory </property> <!-- 配置查询缓存 --> <property name="cache.use_query_cache">true</property> <mapping resource="cn/zzsxt/entity/TUser.hbm.xml" /> </session-factory> </hibernate-configuration>
TUser:
package cn.zzsxt.entity; public class TUser { private int userId; private String userName; private String userPass; public TUser(){ } public TUser(int userId,String userName,String userPass){ this.userId=userId; this.userName=userName; this.userPass=userPass; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } @Override public String toString() { return "TUser [userId=" + userId + ", userName=" + userName + ", userPass=" + userPass + "]"; } }
TUser.hbm.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.zzsxt.entity"> <class name="TUser" table="t_user"> <cache usage="nonstrict-read-write"/> <id name="userId"> <generator class="native"></generator> </id> <property name="userName"></property> <property name="userPass"></property> </class> </hibernate-mapping>
TestSessionLevelCache:
package cn.zzsxt.demo; import java.util.Iterator; import java.util.List; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.query.Query; import cn.zzsxt.entity.TUser; import cn.zzsxt.utils.HibernateUtil; /** *一级缓存:默认是开启状态,不需要额外配置 *一级缓存又称为Session缓存,由Session来管理;和Session的生命周期相同。 *是事务级别的缓存(线程); * @author Think * */ public class TestSessionLevelCache { /** * get方法去查询数据时,首先检查缓存中是否有该数据。如果缓存中有该数据,直接取缓存中的数据。 * 如果缓存中没有,则查询数据库;并且将该数据写入Session缓存中。 */ public static void testGet(){ Session session = HibernateUtil.getSession(); TUser user = session.get(TUser.class, 12); System.out.println(user); TUser user2 = session.get(TUser.class, 12); System.out.println(user2); session.close(); } /** * hibernate中javassist-3.20.0-GA.jar包与MyEclipse自带的JavaEE开发包存在冲突,会导致 * java.lang.ClassCastException异常发生,解决方案:将JavaEE6.0更换成JavaEE7.0 * load方法查询数据,首先检查是否必须查询对象的属性。如果需要查询,那么检查缓存中是否有, * 如果缓存中有该对象,则取缓存中的数据。如果缓存中没有,那么取数据中数据;并且将该数据写入缓存; * load()与get()的区别: * get()方法即时加载,返回的是要查询的对象本身,如果查找不到返回null * load()方法延时加载,返回是代理对象,如果查找不到将抛出org.hibernate.ObjectNotFoundException异常 */ public static void testLoad(){ Session session = HibernateUtil.getSession(); TUser user = session.load(TUser.class, 12); System.out.println(user); TUser user2 = session.load(TUser.class, 12); System.out.println(user2); session.close(); } /** * * list方法查询数据,不会检查Session缓存中是否有数据, * 当从数据库中查询数据以后,会将对象写入Session缓存。 */ public static void testList(){ Session session = HibernateUtil.getSession(); Query<TUser> query = session.createQuery("from TUser"); List<TUser> list = query.list(); for (TUser tUser : list) { System.out.println(tUser); } System.out.println("---------------------"); Query<TUser> query2 = session.createQuery("from TUser"); List<TUser> list2 = query2.list(); for (TUser tUser2 : list2) { System.out.println(tUser2); } System.out.println("--------------------------"); TUser tuser3 = session.get(TUser.class,1); System.out.println(tuser3); session.close(); } /** * n+1和1的问题:iterate()方法--首先查询所有的Id,当使用对象时,再根据id到数据库中查询该对象。 * 所以如果查询所有数据,那么将执行n+1条sql语句。而list查询所有数据只执行1条sql语句。 * 因此,当查询所有对象时应该使用list,而如果查询的是部分数据,那么使用iterate * iterate()/list()区别 * iterate()会先查询所有的Id,当使用对象时在根据id查询缓存,如果缓存中存在将直接返回,否则将根据id查询数据库,会导致n+1问题 * list()会查询所有的数据,只执行1条sql,不会导致n+1问题,但不会检查缓存。 */ public static void testIterator(){ Session session = HibernateUtil.getSession(); Query<TUser> query = session.createQuery("from TUser"); Iterator<TUser> iterator= query.iterate(); while(iterator.hasNext()){ TUser user = iterator.next(); System.out.println(user); } System.out.println("---------------------"); Query<TUser> query2 = session.createQuery("from TUser"); Iterator<TUser> iterator2= query2.iterate(); while(iterator2.hasNext()){ TUser user2 = iterator2.next(); System.out.println(user2); } session.close(); } /** * 缓存管理: * clear():清空缓存 * evict(Object obj):移除缓存中的指定对象 * close():关闭session时会自动清空缓存 */ public static void testClear(){ Session session = HibernateUtil.getSession(); TUser user = session.get(TUser.class, 1); System.out.println(user); // session.clear(); session.evict(user); TUser user2 = session.get(TUser.class, 1); System.out.println(user2); session.close(); } /** * flush():将缓存与数据同步 */ public static void testFlush(){ Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); TUser user = session.get(TUser.class, 1); user.setUserName("admin"); user.setUserPass("admin"); // session.update(user); session.flush();//将缓存与数据库同步 tx.commit(); session.close(); } /** * 需求:批量添加 100w条数据。 * 面临的问题:当调用save方法保存对象时,该对象会变成持久态的对象,即在session的缓存中缓存对象信息,因数据量较大会导致出现内存溢出。 * 解决方案:通过flush方法同步缓存,通过clear方法清空已同步的数据对象。 * */ public static void testBatch(){ Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); for (int i=1;i<1000000;i++) { if(i%50==0){ session.flush(); session.clear(); } TUser tuser = new TUser(i,"test"+i,"test"+i); session.save(tuser); } tx.commit(); session.close(); } public static void main(String[] args) { // testGet(); // testLoad(); // testList(); // testIterator(); // testClear(); // testFlush(); testBatch(); } }
TestSessionFactoryLevelCache:
package cn.zzsxt.demo; import java.util.List; import org.hibernate.Session; import org.hibernate.query.Query; import cn.zzsxt.entity.TUser; import cn.zzsxt.utils.HibernateUtil; /** * hibernate的二级缓存 * @author Think * */ public class TestSessionFactoryLevelCache { /** * 先去一级缓存中查找,如果命中直接返回,否则到二级缓存缓存中查找,如果命中返回, * 如果二级缓存中无要查找的数据,再到数据库中查找。 */ public static void testGet(){ Session session = HibernateUtil.getSession(); TUser user = session.get(TUser.class, 1); System.out.println(user); session.clear();//清空session System.out.println("******************"); TUser user2 = session.get(TUser.class, 1); System.out.println(user2); HibernateUtil.closeClose(); } public static void testList(){ Session session = HibernateUtil.getSession(); Query<TUser> query1 = session.createQuery("from TUser"); query1.setCacheable(true);//启用查询缓存 List<TUser> list = query1.list(); for (TUser tUser : list) { System.out.println(tUser); } session.clear();//清空缓存 System.out.println("******************"); Query<TUser> query2 = session.createQuery("from TUser"); query2.setCacheable(true);//启用查询缓存 List<TUser> list2 = query2.list(); for (TUser tUser : list2) { System.out.println(tUser); } HibernateUtil.closeClose(); } public static void main(String[] args) { // testGet(); testList(); } }
HibernateUtil:
package cn.zzsxt.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static SessionFactory sessionFactory; private static ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); private static Session session; static{ Configuration configuration = new Configuration().configure(); sessionFactory = configuration.buildSessionFactory(); } public static Session getSession(){ session = threadLocal.get(); if(session!=null){ return session; } session = sessionFactory.openSession(); threadLocal.set(session); return session; } public static void closeClose(){ session = threadLocal.get(); if(session!=null&&session.isOpen()){ session.close(); } } }
3.get,load,list,iterate,clear,evict,flush:(Demo在上面)
get:采用的是即时加载,如果查询不到返回null;
load:采用延迟加载,真正使用到查询对象时才发送和执行sql语句,如果找不到,将跑出: org.hibernate.ObjectNotFoundException
lazy:“ture”延迟加载,将查询推迟到真正使用对象时才会发送和执行sql语句,在查询的过程中必须保持session处于可用状态,否则会抛出:org.hibernate.LazyInitializationException
对于class,lazy默认true
对于property,默认false
Many-to-one,默认false
no-proxy:属性应该在实例变量第一次被访问时应延迟抓取(fetche lazily)
set,默认true
proxy,默认true
fetch(抓取策略 select / join):
select 抓取:查询关联对象时,使用select语句(在select抓取下可以使用lazy)
join 抓取:查询关联对象时,使用join(lazy没用)
使用 join可以避免出现N+1的问题
4.Hibernate注解:
TUser:
步骤1:创建实体类并添加注解 package cn.zzsxt.entity2; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity //实体 @Table(name="t_user")//映射的表 public class TUser { @Id//映射表的主键 @GeneratedValue(strategy=GenerationType.IDENTITY)//主键的生产策略 private int userId; @Column(name="userName") private String userName; @Column private String userPass; @Column //映射表的字段 private int userType; @ManyToOne(cascade=CascadeType.ALL)//多对一 @JoinColumn(name="roleId")//外键 private TRole role; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } public int getUserType() { return userType; } public void setUserType(int userType) { this.userType = userType; } public TRole getRole() { return role; } public void setRole(TRole role) { this.role = role; } }
TRole:
package cn.zzsxt.entity2; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.OneToMany; import javax.persistence.Table; @Entity @Table(name="t_role") public class TRole { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int roleId; @Column private String roleName; //一对多 @OneToMany @JoinColumn(name="roleId") private Set<TUser> users = new HashSet<TUser>(); //多对多 @ManyToMany @JoinTable(name="t_role_right",joinColumns=@JoinColumn(name="roleId"),inverseJoinColumns=@JoinColumn(name="rightId"))//关联中间表 private Set<TRight> rights = new HashSet<TRight>(); public int getRoleId() { return roleId; } public void setRoleId(int roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public Set<TUser> getUsers() { return users; } public void setUsers(Set<TUser> users) { this.users = users; } public Set<TRight> getRights() { return rights; } public void setRights(Set<TRight> rights) { this.rights = rights; } }
TRight :
package cn.zzsxt.entity2; import java.util.HashSet; import java.util.Set; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.JoinTable; import javax.persistence.ManyToMany; import javax.persistence.Table; @Entity @Table(name="t_right") public class TRight { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int rightId; @Column private String rightName; @Column private String url; //多对多 @ManyToMany @JoinTable(name="t_role_right",joinColumns=@JoinColumn(name="rightId"),inverseJoinColumns=@JoinColumn(name="roleId")) private Set<TRole> roles = new HashSet<TRole>(); public int getRightId() { return rightId; } public void setRightId(int rightId) { this.rightId = rightId; } public String getRightName() { return rightName; } public void setRightName(String rightName) { this.rightName = rightName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public Set<TRole> getRoles() { return roles; } public void setRoles(Set<TRole> roles) { this.roles = roles; } }
Test:
public class Test { /** * 查找id=1的用户信息,对应的角色信息和权限信息 */ public static void testSelect(){ Session session = HibernateUtil.getSession(); TUser user = session.get(TUser.class, 1); System.out.println("用户名称:"+user.getUserName()); TRole role = user.getRole(); System.out.println("角色名称:"+role.getRoleName()); System.out.println("权限信息:"); Set<TRight> rights = role.getRights(); for (TRight tRight : rights) { System.out.println(tRight.getRightName()); } session.close(); } /** * 添加一个角色"系统管理员",并将所有权限分配给系统管理员 */ public static void testAdd(){ Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); //创建系统管理员角色 TRole role = new TRole(); role.setRoleName("系统管理员"); //查询所有的权限 Query query = session.createQuery("from TRight"); List<TRight> rightsList = query.list(); //为系统管理员分配权限 role.getRights().addAll(rightsList); //新增角色 session.save(role); tx.commit(); session.close(); } public static void main(String[] args) { testAdd(); } } 业务逻辑的实现过程中,往往需要保证数据访问的排他性。因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,
这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其它程序修改。
3.乐观锁:
含义:
认为应用程序并非每一时刻都有高并发,不需要对数据库进行加锁,通过引入版本控制,字段检查,时间戳检查的机制确保同一时刻只能允许一个用户修改数据。
步骤1:在实体类中添加一个version属性,数据类型为int,并提供对应的getter和setter方法:
Userinfo:
package cn.zzsxt.entity3; public class Userinfo { private int userId; private String userName; private String userPass; private int version; public Userinfo() { super(); // TODO Auto-generated constructor stub } public Userinfo(String userName, String userPass) { super(); this.userName = userName; this.userPass = userPass; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPass() { return userPass; } public void setUserPass(String userPass) { this.userPass = userPass; } public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } }
步骤2:在映射文件中添加<version>节点用于标识版本:
<hibernate-mapping> <class name="cn.zzsxt.entity3.Userinfo" table="userinfo"> <id name="userId"> <generator class="native"></generator> </id> <!-- version版本 --> <version name="version"></version> <property name="userName"></property> <property name="userPass"></property> </class> </hibernate-mapping>
步骤3:测试:
TestVersion:
public class TestVersion { public static void testSave(){ Session session = HibernateUtil.getSession(); Transaction tx =session.beginTransaction(); Userinfo user = new Userinfo(); user.setUserName("admin"); user.setUserPass("admin"); session.save(user); tx.commit(); session.close(); } public static void testUpdate(){ Session session = HibernateUtil.getSession(); Transaction tx =session.beginTransaction(); Userinfo user = session.get(Userinfo.class, 1); user.setUserName("test"); session.update(user); tx.commit(); session.close(); } public static void main(String[] args) { testUpdate(); } }
4.悲观锁:(Pessimistic Locking)
含义:
认为应用程序时刻都存在着高并发的情况,必须对数据进行枷锁才能保证数据的安全,悲观锁一般依托于数据库的锁机制完成,如果数据库不支持锁机制,悲观锁将无法正常使用。
基本思想: