Jimoshi_Hibernate 框架学习(三)--正、逆向开发、悲观锁和乐观锁、session中对象的4种状态

来源:互联网 发布:java pageoffice 调用 编辑:程序博客网 时间:2024/05/06 09:53
Jimoshi成长经历:前面的笔记后面再慢慢整理-------方便自己

目录:正向开发、逆向开发、悲观锁和乐观锁、session中对象的4种状态

Hibernate 框架学习(三):

一、正向开发(先根据数据库设计建立实体类,然后进行数据库表设计)

例子:用户( uid,name,rid),角色(rid,rname ),功能(fid,fname),角色_ 功能(rid,fid)

描述:一个用户有一个角色,一个角色对应多个功能,一个功能对应多个角色
(用户与角色之间一对一关系,角色与功能之间多对多的关系)

代码示例(注解配置):

   1、建立对应实体User类、Role类、Func类对象
   
   User实体类的建立,
   @Entity
   @Table(name="t_user")
   public class User {
   private int uid;
   private String uname;
   private Role role;
   @Id
   @GeneratedValue
   public int getUid() { return uid; }
   public void setUid(int uid) { this.uid = uid; }
   public String getUname() { return uname; }
   public void setUname(String uname) { this.uname = uname; }
   @ManyToOne
   public Role getRole() { return role; }
   public void setRole(Role role) { this.role = role;}
}

   Role实体类的建立,
   @Entity
   @Table(name="t_role")
   public class Role {
   private int rid;
   private String rname;
   private Set<Func> funcs;
   @Id
   @GeneratedValue
   public int getRid() { return rid; }
   public void setRid(int rid) { this.rid = rid; }
   public String getRname() { return rname; }
   public void setRname(String rname) { this.rname = rname; }
   @ManyToMany
   public Set<Func> getFuncs() { return funcs; }
   public void setFuncs(Set<Func> funcs) { this.funcs = funcs; }
}
 
   Func实体类的建立,
   @Entity
   @Table(name="t_func")
   public class Func {
   private int fid;
   private String fname;
   private Set<Role> roles;
   @Id
   @GeneratedValue
   public int getFid() { return fid; }
   public void setFid(int fid) { this.fid = fid; }
   public String getFname() { return fname; }
   public void setFname(String fname) { this.fname = fname; }
   @ManyToMany(mappedBy="funcs")
   public Set<Role> getRoles() { return roles; }
   public void setRoles(Set<Role> roles) { this.roles = roles; }
}
   
   2、将对应映射文件加入到session-factory配置(hibernate.cfg.xml)中

   代码示例:
    <mapping class="com.zr.model.Role" />
    <mapping class="com.zr.model.User" />
    <mapping class="com.zr.model.Func" />

   3、测试
    
二、逆向开发(先进行数据库表设计,然后根据数据库设计建立实体类)

  通过工具(HibernateTools-3.2.4.Beta1-R200810311334)把数据库的表自动帮你生成实体和注解或者XML
  工具类的使用:直接将工具放入Eclipse安装包中

  引入工具类(在pom.xml配置文件中配置)
  代码示例:
  <exclusions>
    <exclusion>
    <artifactId>javassist</artifactId>
    <groupId>javassist</groupId>
    </exclusion>   
  </exclusions>


步骤示例:创建数据库表---》 window--->Show View--->other--->Data Source Explorer --->右键Database Connections --->new--->MySQL--->输入密码并且把URL中改成你需要连接的数据库名--->点击Drivers后面第一个图标--->Name/Type中选中5.1版本--->JAR List中添加mysql-connector-java-5.1.18-bin.jar点击Edit--->window--->Show view --->other--->Hibernate Configurations --->右键Add Configurations--->Browse选中你的需要添加的项目名--->Datavase connection 中选中MySql--->Apply--->ok--->点击运行键右边第二个图标的下箭头选中Hibernate Code Generation Configurations --->Main中的Output directory 选择你要放表的地址--->package填写你要放入的包(com.zr.model)--->Exporters中的 勾选Generate EJB3 annotations,Domain code(.java){注解,如果配置xml文件选中Hibernate XML Mappings}--->Run

运行结束后需要注意:1.泛型需要指定  2. lazy 属性删掉

三、悲观锁和乐观锁(不同用户操作同一个数据)

 1、悲观锁(需要由底层数据库提供支持,使用for update)
 描述:指的是对数据被外界修改持保守态度。假定任何时刻存取数据时,都可能有另一个客户也正在存取同一笔数 据,为了保持数据被操作的一致性,于是对数据采取了数据库层次的锁定状态,依靠数据库提供的锁机制来实现
 
 基于jdbc实现的数据库加锁如下:
 select * from account where name="mary" for update
(在更新的过程中,数据库处于加锁状态,任何其他的针对本条数据的操作都将被延迟,本次事务提交后解锁。)

显示用户指定的方式:
 Session.get()  
 Session.load() 指定锁的方式
 Session.lock()
 Query.setLockMode()

 测试:
 //加锁
 @Test
 public void test1(){
 User user = (User) session.get(User.class, Integer.valueOf(1),LockMode.UPGRADE);
 Role currentUserRole = user.getRole();
 Set<Func> funcs = currentUserRole.getFuncs();
 for (Func func : funcs) {
    System.out.println(func.getFname());
    }
 }

 2、乐观锁(为对象加上 一个版本号或者是时间戳)

 描述:乐观的认为资料的存取很少发生同时存取的问题,因而不作数据库层次上的锁定,为了维护正确的数据,乐观锁定采用应用程序上的逻辑实现版本控制的方法。

 可以利用Hibernate提供的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>元素 都具有版本控制功能:
 <version>元素利用一个递增的整数来跟踪数据库表中记录的版本
 <timestamp>元素用时间戳来跟踪数据库表中记录的版本。
 代码示例:
  1.在类中定义一个代表版本信息的属性:
   private int version;
  (进行get,set)
  2.在表中定义一个代表版本信息的字段
  3.在hbm.xml配置文件中用<version>元素来建立类的version属性与表中VERSION字段的映射:
   <id name="id" type="long" column="ID">
     <generator class="increment"/>
   </id>
   <version name="version" column="VERSION" />
  4.找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException。
  在应用程序中应该捕获该异常,这种异常有两种处理方式:
   4.1。自动撤销事务,通知用户账户信息已被其他事务修改,需要重新开始事务。
   4.2。通知用户账户信息已被其他事务修改,显示最新存款余额信息,由用户决定如何继续事务,用户也可以决定立刻撤销事务。
  5.如果数据库表中不包含代表版本或时间戳的字段,Hibernate提供了其他实现乐观锁的办法。把<class>元素的optimistic-lock属性设为“all”。

四、session中对象的4种状态

注:session 缓存(拿空间换时间)我们用的session 一级缓存,在缓存中就使用OID标识符

 1、临时状态(transient):刚刚用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的  Java对象被称为临时对象。
 (session缓存当中没有,数据库中当中也没有)

 2、持久化状态(persistent):已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象被称为持久 化对象。
(session缓存当中有,数据库中当中也有)

 3、游离状态(detached):已经被持久化,但不再处于Session的缓存中。处于游离状态的Java对象被称为游离对 象。
(session缓存当中没有,数据库中当中有)

 4、删除状态(removed):OID不为null。从一个Session实例的缓存中删除。被删除对象和数据库中的相关记录对 应。Session已经计划将其从数据库中删除。Session在清理缓存时,会执行SQL delete语句,删除数据库中的相应 记录。一般情况下,应用程序不应该再使用被删除的对象。
(session缓存当中没有,数据库中当中也没有)

代码示例:
 @Test
 public void test2(){
 session = sf.openSession();
 session.beginTransaction();    
  //临时状态
 Student s = new Student();
 s.setSname("wwj");
 //持久化状态
 session.save(s);
 session.delete(s);
 session.getTransaction().commit();
 //关闭session
 session.close();
 //游离状态
 // System.out.println(s.getSname());
 //删除状态
 System.out.println(s.getSname());
 }


 //将游离状态变为持久状态
 @Test
 public void update(){
  Session session1 = sf.openSession();
  session1.beginTransaction();
  Student s = new Student();
  s.setSname("yyy");
  session1.save(s);
  session1.getTransaction().commit();
  session1.close();
  Session session2 = sf.openSession();
  session2.beginTransaction();
  s.setSname("bcd");
  session2.update(s);
  session2.load(Student.class, Integer.valueOf(19));
  System.out.println(s.getSname());
  session2.getTransaction().commit();
  session2.close();
 }

 5、关于get  和  load 方法的区别(都是优先从session一级缓存中寻找)

 采用get加载数据,如果数据库中不存在相应的数据,那么返回null;

 采用load加载数据,如果数据库中不存在相应的数据,那么抛出ObjectNotFoundException
 load方法可返回实体的代理类实例,如果需要用到数据,在执行SQL语句。而get方法永远直接返回实体类。直接就  发出了SQL语句

 代码示例:
  @Test
  public void testLoad(){
    Session session = sf.openSession();
    session.beginTransaction();
    Student s = (Student) session.load(Student.class, Integer.valueOf(2));
    System.out.println(s);
    session.getTransaction().commit();
    session.close();
  }
  @Test
  public void testGet(){
    Session session = sf.openSession();
    session.beginTransaction();
    Student s = (Student) session.get(Student.class, Integer.valueOf(2));
    System.out.println(s);
    s.getSname();
    session.getTransaction().commit();
    session.close();
  }
1 0
原创粉丝点击