Hibernate(5)session的方法

 1. Session缓存  Session缓存(Hibernate一级缓存),在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期。
Session 缓存可减少 Hibernate 应用程序访问数据库的频率。
两次获取同一个对象:
①第一次获取Users对象时会去数据库中查找,找到之后把Users对象的引用赋给user引用变量,同时还会把Users对象的引用给到Session缓存中,
②若再次查找同一个Users变量,首先会去Session中找有没有,若缓存中有就不去查询数据库,直接从缓存中获取
    /**
* Session缓存(Hibernate一级缓存),在 Session 接口的实现中包含一系列的 Java 集合,
*这些 Java 集合构成了 Session 缓存。
*只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期
*Session 缓存可减少 Hibernate 应用程序访问数据库的频率。
* 两次获取同一个对象:
* ①第一次获取Users对象时会去数据库中查找,找到之后把Users对象的引用赋给user引用变量,
* 同时还会把Users对象的引用给到Session缓存中,
* ②若再次查找同一个Users变量,首先会去Session中找有没有,若缓存中有就不去查询数据库,直接从缓存中获取
*/
@Test
public void testSessionCache(){
Users user = (Users) session.get(Users.class, 8);
System.out.println(user); Users user2 = (Users) session.get(Users.class, 8);
System.out.println(user2); }
2. flush方法:使数据表中的记录和Session缓存中的对象的状态保持一致,为保持一致,则可能会发送对应的SQL语句
* 提下情况会调用该方法:
* 1.在Transaction的commit方法中,先调用session的Flush方法,在提交事务
* 2.显式的调用flush()方法可能会发送SQL语句,但不会提交事务
* 3.注意:在未提交事务或显式的调用session.flush()方法之前,也有可能进行flush()操作。
* ①.执行HQL或QBC查询,会先进行flush()操作,以得到数据表的最新的记录
* ②.若记录的ID是由底层数据库使用自增的方式生成的则在调用save()方法后,就会立即发送INSERT语句,因为save方法后
* 必须保证对象的ID是存在的
/**
* flush方法:使数据表中的记录和Session缓存中的对象的状态保持一致,为保持一致,则可能会发送对应的SQL语句
*提下情况会调用该方法:
* 1.在Transaction的commit方法中,先调用session的Flush方法,在提交事务
* 2.显式的调用flush()方法可能会发送SQL语句,但不会提交事务
* 3.注意:在未提交事务或显式的调用session.flush()方法之前,也有可能进行flush()操作。
* ①.执行HQL或QBC查询,会先进行flush()操作,以得到数据表的最新的记录
* ②.若记录的ID是由底层数据库使用自增的方式生成的则在调用save()方法后,就会立即发送INSERT语句,因为save方法后
*必须保证对象的ID是存在的
*/
@Test
public void testSessionFlush(){
Users users = (Users) session.get(Users.class, 8);
users.setLoginName("Jack"); //session.flush();
//System.out.println("flush()"); //HQL查询
Users user2 = (Users) session.createCriteria(Users.class).uniqueResult();
System.out.println(user2);
}
//使用save()方法,会立即执行SQL语句,而不用等到事务提交,其他方法需要等到事务提交之后到能执行SQL语句
@Test
public void testSessionFlush2(){
Users user = new Users("mengqi", "123", "孟奇", "河南省郑州市", "19843244908", "163@.com", new Date());
session.save(user);
}
 3. reflush():获取数据表中最新的记录,该方法会强制执行查询,
* 手动修改表中的记录,使用reflush(),再次打印user时,打印的记录就会和之前打印的不一致,此时打印的是手动修改后的记录,即最新是记录,若打印的不是最新的则是MYSQL数据库的隔离级别问题,MYSQL默认的隔离级别为REPEATABLE READ(可重复读),需要改成READ COMMITED(读已提交)。
* 在Hibernate的配置文件中,可以显示的设置隔离级别,每一个隔离级别都对应一个数字
* 1对应READ UNCOMMITED
* 2对应READ COMMITED
* 4对应REPEATABLE READ
* 8对应SERIALIZEABLE
*Hibernate通过Hibernate配置文件指定,Hibernate.connection.isolation属性设置事务的隔离级别
    /**
* reflush():获取数据表中最新的记录,该方法会强制执行查询,
* 手动修改表中的记录,使用reflush(),再次打印user时,打印的记录就会和之前打印的不一致,此时打印
* 的是手动修改后的记录,即最新是记录,若打印的不是最新的则是MYSQL数据库的隔离级别问题,
* MYSQL默认的隔离级别为REPEATABLE READ(可重复读),需要改成READ COMMITED(读已提交)
* 在Hibernate的配置文件中,可以显示的设置隔离级别,每一个隔离级别都对应一个数字
* 1对应READ UNCOMMITED
* 2对应READ COMMITED
* 4对应REPEATABLE READ
* 8对应SERIALIZEABLE
*Hibernate通过Hibernate配置文件指定,Hibernate.connection.isolation属性设置事务的隔离级别
*/
@Test
public void testReFlush(){
Users user = (Users) session.get(Users.class, 8);
System.out.println(user); //在此打印断点,打印出的user与上一个打印的user没有什么不同
System.out.println(user); //此时手动修改了表中的记录,使用reflush(),再次打印user时,打印的记录就会和之前打印的不一致,此时打印
//的是手动修改后的记录,即最新是记录,若打印的不是最新的则是MYSQL数据库的隔离级别问题,
//MYSQL默认的隔离级别为REPEATABLE READ(可重复读),需要改成
session.refresh(user);
System.out.println(user);
}
 4. claer():清理缓存,两次查询同一条记录,中间使用clear()清理之后,第二条查询也会发送一条记录
    /**
* claer():清理缓存,两次查询同一条记录,中间使用clear()清理之后,第二条查询也会发送一条记录
*/
@Test
public void testClear(){
Users users = (Users) session.get(Users.class, 8);
session.clear();
Users users2 = (Users) session.get(Users.class, 8);
}
 5. save()
* ①把对象加入到Session缓存中,使一个临时对象变为持久化对象
* ②选用映射文件指定的标识符生成器,为对象分配ID
* ③在flush()缓存时会发送一条INSERT语句
* ④在save()方法之前设置ID属性值是无效的,但不抛出异常
* ⑤持久化对象的ID是不能被修改的
    /**
* save():
* ①把对象加入到Session缓存中,使一个临时对象变为持久化对象
* ②选用映射文件指定的标识符生成器,为对象分配ID
* ③在flush()缓存时会发送一条INSERT语句
* ④在save()方法之前设置ID属性值是无效的,但不抛出异常
* ⑤持久化对象的ID是不能被修改的
*/
@Test
public void testSave(){
Users user = new Users("wangqiang", "123", "王强", "河南省", "18292389876", "163@qq.com", new Date());
//save()方法前后的对象区别在于save()之后会给对象分配ID
System.out.println("user:"+user);
session.save(user);
System.out.println("user:"+user); //在save()方法前修改ID是无效的
Users user2 = new Users("wangqiang", "1234", "王强", "河南省", "18292389876", "163@qq.com", new Date());
user2.setId(100);
session.save(user2);
System.out.println("user2:"+user2);//为id赋值失败
user2.setId(100);
}
 6. Persist():也会执行INSERT操作,作用与save()一致
与save的主要内容区别:
persist把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。
save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert
    /**
* Persist():也会执行INSERT操作,作用与save()一致,与save的主要内容区别:
persist把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。
save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert
*:
*/
@Test
public void testPersist(){
Users user = new Users("wangwei", "123", "王伟", "河南省", "19483928495", "163@qq.com", new Date());
user.setId(100);
session.persist(user);
}
 7. GET()和Load()的区别
* 1.get方法会立即加载该对象,立即执行查询
* load方法,若不使用该对象,则不会立即加载,而返回一个代理对象,不会立即执行查询操作
* 2.若数据表中没有对应的记录get返回null,load会抛出异常
* 3.load方法可能会抛出懒加载异常,因为load方法是在使用对象的时候再执行查询操作,
* 假如在使用对象之前把session关闭,即需要初始化代理对象之前已经关闭了Session,同时又在使用加载的对象,
* 就会出现懒加载异常,若不使用加载的对象,则没有问题
* get在使用对象之前关闭session则没有问题。
     * GET()和Load()的区别
* 1.get方法会立即加载该对象,立即执行查询
* load方法,若不使用该对象,则不会立即加载,而返回一个代理对象,不会立即执行查询操作
* 2.若数据表中没有对应的记录get返回null,load会抛出异常
* 3.load方法可能会抛出懒加载异常,因为load方法是在使用对象的时候再执行查询操作,
* 假如在使用对象之前把session关闭,即需要初始化代理对象之前已经关闭了Session,同时又在使用加载的对象,
* 就会出现懒加载异常,若不使用加载的对象,则没有问题
* get在使用对象之前关闭session则没有问题。
*
*/
@Test
public void testGet(){
Users user = (Users) session.get(Users.class, 5);
session.close();
System.out.println(user);
}
@Test
public void testLoad(){
Users user = (Users) session.load(Users.class, 5);
session.close();//使用对象前关闭session,出现懒加载异常org.hibernate.LazyInitializationException,不使用则没有问题
System.out.println(user);
}
 8. Update()
* 1.若更新一个持久化对象,不需要显示的调用update()方法,因为在调用Transaction的commit方法时,会先执行
*Session的flush()方法
* 2.更新一个游离对象时,需要显式的调用Session的update方法,可以把一个游离对象变为一个持久化对象
*注意:
* ①.若显式的调用Session的update方法,则无论游离的对象中属性有没有变化,都会发送update语句
*可以使用Xxx.hbm.xml文件的class节点设置select-before-update=true(默认为false),
*但通常并不设置此属性
* ②.若数据表中没有对应的记录,但还调用了update方法,会抛出异常
* ③.当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象,
* 会抛出异常
/**
* Update()
* 1.若更新一个持久化对象,不需要显示的调用update()方法,因为在调用Transaction的commit方法时,会先执行
*Session的flush()方法
* 2.更新一个游离对象时,需要显式的调用Session的update方法,可以把一个游离对象变为一个持久化对象
*注意:
* ①.若显式的调用Session的update方法,则无论游离的对象中属性有没有变化,都会发送update语句
*可以使用Xxx.hbm.xml文件的class节点设置select-before-update=true(默认为false),
*但通常并不设置此属性
* ②.若数据表中没有对应的记录,但还调用了update方法,会抛出异常
* ③.当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象,
* 会抛出异常
*/
@Test
public void testUpdate(){
Users user = (Users) session.get(Users.class, 8);
//1.
transaction.commit();
//关闭session,user对象成为游离对象
session.close(); //②更改游离对象的id,使update方法更新一个数据库中不存在的记录,结果是抛出异常
//user.setId(100); //虽然又开启了一个Session,但是这个Session与上一个Session并没有联系。
session = sessionFactory.openSession();
transaction = session.beginTransaction(); //③虽然这只是一个简单的查询,但是执行查询会在session缓存中关联ID为8的一个持久化对象,
//当显式执行下面的update方法时,会把id为8的游离对象也关联到session缓存中,但是Session缓存中不能有
//两个相同ID的对象
Users users = (Users) session.get(Users.class, 8); user.setLoginName("Nick");
//2.只有显式的调用session的update方法才能让设置的LoginName属性生效
session.update(user);
}
 9. SaveOrUpdate():若是一个临时对象则执行save,游离对象执行update
* 注意:
* 1.若OID不为null,但数据表中没有与之对应的记录则会抛出异常,因为虽然OID不为空,也是一个游离对象,
*但是数据表中没有对应的记录无法执行update语句。
* 2.了解:OID值等于id的unsaved-value属性值的对象,也被认为是一个游离对象,unsave-value是映射文件中id子节点的属性
    /**
* SaveOrUpdate():若是一个临时对象则执行save,游离对象执行update
* 注意:
* 1.若OID不为null,但数据表中没有与之对应的记录则会抛出异常,因为虽然OID不为空,也是一个游离对象,
*但是数据表中没有对应的记录无法执行update语句。
* 2.了解:OID值等于id的unsaved-value属性值的对象,也被认为是一个游离对象,unsave-value是映射文件中id子节点的属性
*/
@Test
public void testSaveOrUpdate(){
//临时对象,调用saveOrUpdate()方法,执行insert语句
Users user = new Users("wangmei", "123", "王梅", "河南省", "19483928495", "163@qq.com", new Date());
//设置id为8对应数据库表中存在的记录,调用saveOrUpdate()方法,执行update语句
user.setId(8); //该值等于映射文件中id子节点的unsave-value属性值,所以可以调用saveOrUpdate()方法,执行insert语句
user.setId(100);
session.saveOrUpdate(user);
}
 10. Delete():Session的delete()方法既可以删除一个游离对象,又可以删除一个持久化对象,
* ①只要OID和数据表中一条记录对应,就会准备执行Delete操作,若OID在数据表中没有对应的记录,则会抛出异常。
* ②可以通过设置Hibernate配置文件中的一个hibernate.use_identifier_rollback 属性
*来把持久化对象或游离对象的 OID 设置为 null, 使它们变为临时对象
/**
* Delete():Session的delete()方法既可以删除一个游离对象,又可以删除一个持久化对象,
* ①只要OID和数据表中一条记录对应,就会准备执行Delete操作,若OID在数据表中没有对应的记录,则会抛出异常。
* ②可以通过设置Hibernate配置文件中的一个hibernate.use_identifier_rollback 属性
*来把持久化对象或游离对象的 OID 设置为 null, 使它们变为临时对象
*/
@Test
public void testDelete(){
//因为数据表中id为8的记录已经被删除了,所以该对象是游离对象
// Users user = new Users();
// user.setId(8); //持久化对象也可以删除
Users user = (Users) session.get(Users.class, 7); session.delete(user); //执行完delete之后,该对象还是有ID值的,若之后想要对该对象执行saveOrUpdate方法,则会强制发送update语句
//但是,数据表中已经没有这条记录,就会抛异常
System.out.println(user);
}
 11. Evict():从Session中把指定的持久化对象移除
/**
* Evict():从Session中把指定的持久化对象移除
*
*/
@Test
public void testEvict(){
Users user = (Users) session.get(Users.class, 4);
Users user2 = (Users) session.get(Users.class, 5); user.setLoginName("Lucy");
user2.setLoginName("Jack"); //虽然更新了两个对象的值,但是由于user对象从session中移除,所以只对user2执行了update
session.evict(user);
}
 12.  doWork():调用存储过程,需要获取Connection
/**
* doWork():调用存储过程,需要获取Connection
*/
@Test
public void testDoWork(){
session.doWork(new Work() { @Override
public void execute(Connection conn) throws SQLException {
//没有配置C3P0数据源时连接是从数据库中获取的:com.mysql.jdbc.JDBC4Connection@42f92dbc
//配置C3P0数据源之后从连接池中获取连接:com.mchange.v2.c3p0.impl.NewProxyConnection@66ee2542
System.out.println(conn); //调用存储过程
}
});
}
 13. dynamic-update:class节点的属性不设置的话执行更新操作的话,会更新全部的属性值,设置之后仅更新修改后的属性值
*好处:减少数据库的操作
    /**
* dynamic-update:class节点的属性,不设置的话执行更新操作的话,会更新全部的属性值,设置之后仅更新修改后的属性值
*好处:减少数据库的操作
*/
@Test
public void testdynamicUpdate(){
Users user = (Users) session.get(Users.class, 4);
user.setLoginPwd("1234");
}
 14. 主键生成策略:increment主键生成器时会出现并发的问题,连续执行两次该方法,模仿两个线程同时访问同一个数据表
* 由于是自增,但是是两个线程,所以会造成两个线程的id自增之后,id值重复,无法执行SQL语句
    /**
* 主键生成策略:increment主键生成器时会出现并发的问题,连续执行两次该方法,模仿两个线程同时访问同一个数据表
* 由于是自增,但是是两个线程,所以会造成两个线程的id自增之后,id值重复,无法执行SQL语句
* @throws InterruptedException
*/
@Test
public void testIdGenerator() throws InterruptedException{
Users user = new Users("wangwei", "123", "王伟", "河南省", "19483928495", "163@qq.com", new Date());
session.save(user); //Thread.sleep(5000);
}
 15.  ①派生属性②Java 时间和日期类型的 Hibernate 映射
/**
* ①派生属性
* ②Java 时间和日期类型的 Hibernate 映射
*/
@Test
public void testPropertyUpdate(){
Users user = (Users) session.get(Users.class, 1);
user.setLoginName("AAA");
System.out.println(user.getDesc()); System.out.println(user.getDate().getClass());
}
 16. 大文件属性映射
    /**
* 大文件属性映射数据库
* @throws Exception
*/
@Test
public void testBlob() throws Exception{
Users user = new Users("wangwei", "123", "王伟", "河南省", "19483928495", "163@qq.com", new Date());
user.setContent("CONTENT"); //文件的输入流
InputStream inputStream = new FileInputStream("1.jpg");
Blob image = Hibernate.getLobCreator(session).createBlob(inputStream, inputStream.available());
user.setImage(image);
session.save(user); Users user2 = (Users) session.get(Users.class, 1);
Blob image2 = user2.getImage(); //输出流输出文件
InputStream inputStream2 = image2.getBinaryStream();
//仅显示文件的大小
System.out.println("图片大小:" + inputStream2.available());
}
 17.映射组成关系:即一个没有id的自定义类是另一个自定义类中的属性,那么这个属性可以使用映射组成关系来映射
/**
* 映射组成关系:即一个没有id的自定义类是另一个自定义类中的属性,那么这个属性可以使用映射组成关系来映射
*/
@Test
public void testComponent(){
Worker worker = new Worker();
Pay pay = new Pay();
pay.setMonthlyPay(1000);
pay.setYearPay(12000);
pay.setVocationWithPay(5); worker.setName("ABC");
worker.setPay(pay);
session.save(worker);
}

以上方法的需要的 实体类

Users.java

package com.test.withXml.entity;

import java.io.Serializable;
import java.sql.Blob;
import java.util.Date; public class Users implements Serializable { private static final long serialVersionUID = 1L;
private Integer id;
private String loginName;
private String loginPwd;
private String name;
private String address;
private String phone;
private String mail;
//日期格式
private Date date;
//派生的属性
private String Desc;
//大文本属性
private String content;
//二进制文件
private Blob image; public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Blob getImage() {
return image;
}
public void setImage(Blob image) {
this.image = image;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLoginName() {
return loginName;
}
public void setLoginName(String loginName) {
this.loginName = loginName;
}
public String getLoginPwd() {
return loginPwd;
}
public void setLoginPwd(String loginPwd) {
this.loginPwd = loginPwd;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getMail() {
return mail;
}
public void setMail(String mail) {
this.mail = mail;
}
public String getDesc() {
return Desc;
}
public void setDesc(String desc) {
Desc = desc;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
//1.
public Users(String loginName, String loginPwd, String name,
String address, String phone, String mail, Date date) {
super();
this.loginName = loginName;
this.loginPwd = loginPwd;
this.name = name;
this.address = address;
this.phone = phone;
this.mail = mail;
this.date = date;
}
//2.
public Users() {
}
@Override
public String toString() {
return "Users [loginName=" + loginName + ", loginPwd=" + loginPwd
+ ", name=" + name + ", address=" + address + ", phone="
+ phone + ", mail=" + mail + ", date=" + date + "]";
}
}

Worker.java

package com.test.withXml.entity;
/**
* @author
* @version: 1.0
* @Created on: 2018-1-17 下午10:03:14
* 类说明:工人
*/
public class Worker { private Integer id;
private String name;
private Pay pay;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Pay getPay() {
return pay;
}
public void setPay(Pay pay) {
this.pay = pay;
} }

映射文件User.hbm.xml

<!-- 映射文件 -->

<hibernate-mapping>
<!-- class节点中的name属性对应实体类的名字,table属性对应数据表的名字,catalog对应数据库的名字 -->
<class name="com.test.withXml.entity.Users" table="users"
catalog="hibernate_xml" dynamic-update="true">
<!-- class节点下必须有一个<id>节点,用于定义实体类的标识属性(对应数据表中的主键),
id节点的name属性对应实体类的属性,type对应该属性的Java类型
-->
<id name="id" type="java.lang.Integer" unsaved-value="100">
<!-- column用于指定数据库表的列名 -->
<column name="Id"></column>
<!-- generator用于指定主键的生成器策略 ,使用native表示让底层数据库主键自增的方式生成,使用这种方式
产生的ID会在执行Session的save()方法的时候,先执行SQL语句,在提交事务的意外情况。
hilo表示使用Hibernate高低算法生成ID,使用该算法时,要在数据库中建立一张额外的表,
默认表名为hibernate_unique_key,默认字段为integer类型,名称是next_hi,并设置初始值-->
<generator class="native"></generator>
</id>
<!-- properties节点与id类似,用于映射普通属性 -->
<property name="loginName" type="java.lang.String">
<column name="LoginName" length="50"></column>
</property>
<property name="loginPwd" type="java.lang.String">
<column name="LoginPwd" length="16"></column>
</property>
<property name="name" type="java.lang.String">
<column name="Name" length="16"></column>
</property>
<property name="address" type="java.lang.String">
<column name="Address" length="16"></column>
</property>
<property name="phone" type="java.lang.String">
<column name="Phone" length="16"></column>
</property>
<property name="mail" type="java.lang.String">
<column name="Mail" length="20"></column>
</property> <!-- 映射派生属性,即对象中需要一个属性但是数据表中不需要再添加一个字段,使用派生属性即可 -->
<property name="desc" formula="(SELECT concat(LoginName, ': ', LoginPwd) FROM users n WHERE n.id = id)"></property> <!-- 映射date(日期)、time(时间)、timestamp(时间戳),此时映射的是时间 -->
<property name="date" type="date">
<column name="Date" length="20"></column>
</property> <!-- 映射大文本属性 -->
<property name="content">
<column name="Content" sql-type="mediumtext"></column>
</property>
<property name="image">
<column name="Image" sql-type="mediumblob"></column>
</property> </class>
</hibernate-mapping>

Worker.hbm.xml

<hibernate-mapping package="com.test.withXml.entity">
<class name="Worker" table="WORKER">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<!-- 映射组成关系,即该属性不是一个基本数据类型,而是一个自定义的类,的引用类型 -->
<component name="pay" class="Pay">
<!-- 指定组成关系的组件属性 -->
<property name="monthlyPay" column="MonthlyPay"></property>
<property name="yearPay" column="YearPay"></property>
<property name="vocationWithPay" column="VocationWithPay"></property>
</component>
</class>
</hibernate-mapping>
上一篇:如何使用数据库保存session的方法简介


下一篇:WCF 传输的序列化