Configuration
Configuration接口的作用是对Hibernate进行配置,以及对它进行启动,一般只创建一个实例。在Hibernate的启
动过程中,Configuration类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。
1.Configuration的创建方式
1.1 hibernate.properties配置文件
启动hibernate时会去读取properties作为默认配置文件,该配置文件没有提供添加Hibernate持久化类的方式,
因此使用hibernate.properties作为配置文件时,必须调用Configuration对象的addAnnotatedClass()或
addPackage()方法添加持久化类。
Configuration cfg = new Configuration().configure().addAnnotatedClass(com.hibernate.demo.domain.News.class);
//StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
//sessionFactory = cfg.buildSessionFactory(serviceRegistry);
sessionFactory = cfg.buildSessionFactory();
1.2 hibernate.cfg.xml作为配置文件
//hibernate的配置文件如果自定义的话就要指定文件名
//Configuration config = new Configuration().configure("myhibernate.cfg.xml");
//hibernate的配置文件名默认是hibernate.cfg.xml,可以不用指定
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
1.3 无配置文件
Configuration对象提供了下列方法进行持久化类和设置配置属性:
1.Configuration.addAnnotatedClass(Class annotatedClass) :添加一个持久化类。
2.Configuration.addPackage(String packageName):添加指定包下面所有持久化类
3.Configuration.setProperties(Properties properties):通过Properties实例设置属性。
4.Configuration.setProperty(String propertyName,String value):设置单个属性。
// 实例化Configuration,不加载任何配置文件
Configuration conf = new Configuration()
// 通过addAnnotatedClass()方法添加持久化类
.addAnnotatedClass(org.crazyit.app.domain.News.class)
// 通过setProperty设置Hibernate的连接属性。
.setProperty("hibernate.connection.driver_class"
, "com.mysql.jdbc.Driver")
.setProperty("hibernate.connection.url"
, "jdbc:mysql://localhost/hibernate")
.setProperty("hibernate.connection.username" , "root")
.setProperty("hibernate.connection.password" , "admin")
.setProperty("hibernate.c3p0.max_size" , "20")
.setProperty("hibernate.c3p0.min_size" , "1")
.setProperty("hibernate.c3p0.timeout" , "5000")
.setProperty("hibernate.c3p0.max_statements" , "100")
.setProperty("hibernate.c3p0.idle_test_period" , "3000")
.setProperty("hibernate.c3p0.acquire_increment" , "2")
.setProperty("hibernate.c3p0.validate" , "true")
.setProperty("hibernate.dialect"
, "org.hibernate.dialect.MySQL5InnoDBDialect")
.setProperty("hibernate.hbm2ddl.auto" , "update");
//以Configuration实例创建SessionFactory实例
//StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
//SessionFactory sf = conf.buildSessionFactory(serviceRegistry);
SessionFactory sf = conf.buildSessionFactory();
2.Configuration的其他重要方法
2.1config() ; //通过指定参数来传递的方式读取配置文件
File file = new File("c:\\Hibernate.xml");
Configuration config = new Configuration().config(file);
2.2 setProperties() //读取properties文件
Properties properties = Porperties.load("a.properties");
Configuration configure = new Configuration().setProperties(properties);
2.3 addProperties()
SessionFactory
SessionFactory是用来创建session的工厂类,一般在一个项目初始化的时候构造一个实例(对应一个数据库,
有多个数据库时可以为每个数据库创建一个该实例),比如在一个公共静态类中初始化一个SessionFactory的
readonly常量等等,它充当存储数据源的代理,它是线程安全的,可以被多个线程调用,并且是重量级的,所以
只需要创建一个实例即可。
1 创建方式
try{
Configuration() config= new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
}catch(HibernateException e){
throw new RuntimeException(e.getMessage,e);
}
session
1.hibernate中的实例对象
存在三种中状态:
1.1 自由状态(瞬时状态):对象被实例化,但是还没有给对象的OID(对象的唯一的唯一标识符即表中的主键)属性赋值。
User user = new User(); //此时的user处于自由状态
1.2 游离状态(托管状态):实例化对象的OID属性也被赋值。、
user.setId(1); //此时的user处于游离状态(还没有进行持久化操作,数据库中还没有对应的数据)
1.3 持久状态:仅与一个session相关联。
session.save(user); //此时的user处于持久状态 (数据库中存在对应的数据)
2.session操作对象的区别
2.1 操作游离对象
User user = new User();
user.setId(2);
user.setName("石破天");
user.setAge(25);
2.11 save()方法
session.save(user);
此时hibernate会执行一条sqlinsert语句,当数据库中存在这条记录时,就会抛异常。
2.12 saveOrUpdate()方法
session.saveOrUpdate(user);
当数据库中没有对应的数据时,hibernate会执行一条sqlinsert语句。当数据库中有这条记录时,
hibernate的脏检查机制会自动检查游离对象的属性值与数据库中对应字段的值是否一致,如果
一致,则什么都不用做,如果不一样则执行sqlupdate语句。
例如:user中的 name="石破天",数据库对应表中的对应字段 name="石破天",name的值一样,
则什么也不会做,否则就会执行更新语句。
2.13 persist()方法 //与save()方法差不多
2.14 update()方法
session.update(user);
执行一条sqlupdate语句,如果数据库中不存在对应的记录就会抛异常。
2.15 delete()方法
session.delete(user);
执行一条sqldelete语句,如果数据库中不存在对应的记录就会抛异常。
2.16 merge() 方法
这个方法基本和saveOrUpdate() 方法的用法相似。
2.17 lock() 方法
session.lock(user,LockMode.NONE); //必须在后面有一条setter 方法,不然Hibernate 什么也不会做。
user.setAge(29);
当数据库中存在这条记录时,Hibernate 总会执行一条SQLUPDATE 语句;当数据库中不存这条记录时,
就会抛出异常。
2.18 replicate() 方法
session.replicate(user,ReplicationMode.EXCEPTION);
这个方法基本和save() 方法和 persist() 方法的用法相似。
2.2 session操作持久态对象
2.21 load() 方法
通过OID 从数据库中抓取数据,并把数据加载到一个新实例对象上。
User user =(User) session.load(User.class, 1); // 此时的 user 处于持久状态
调用这个方法时,当数据库中存在这条记录时,Hibernate 会执行一条 SQLSELECT 语句;当数据库中没
有这条记录时,会抛出异常。
2.22 get() 方法
通过OID 从数据库中抓取数据,并把数据加载到一个新实例对象上。
User user = (User) session.get(User.class, 1); // 此时的 user 处于持久状态
调用这个方法时,当数据库中存在这条记录时,Hibernate 会执行一条 SQLSELECT 语句;当数据库中没
有这条记录时,user = null。
2.23 save() 方法
User user = (User) session.load(User.class, 1);
user.setName("JOE");
session.save(user);
Hibernate的脏检查机制会自动检查对象的属性(name)值与数据库中对应的字段(name)值是否一样。如果一
样就什么也不做;如果不一样就执行SQLUPDTE 语句。
2.24 saveOrUpdate()方法
这时的saveOrUpdate() 和 save() 方法用法一样。
2.25 persist() 方法
与 save() 方法一样。
2.26 update() 方法
与 save() 方法一样。
2.27 delete() 方法
session.delete(user);
Hibernate 执行一条 SQLDELETE 语句,这时 user 变为游离状态。
2.28 merge() 方法:与 update() 方法一样。
2.29 lock() 方法:与 update() 方法一样。
2.210 session.lock(user,LockMode.NONE); //此时不必在后面有一条setter 方法。
2.211 replicate() 方法
与 update() 方法一样。
session.replicate(user,ReplicationMode.EXCEPTION);
2.212 flush() 方法
与 update() 方法一样。
User user = (User) session.load(User.class, 1);
user.setName("JOE");
session.flush();
2.213 refresh() 方法
User user = (User) session.get(User.class, 1);
user.setName("JOE");
session.flush();
session.refresh(user);
2.214 clear() 方法
清空Session 缓存
session.clear();
2.215 evcit() 方法:把持久对象从Session 缓存中移除。
session.evcit(user);
3 openSession()与getCurrentSession()
区别:1.getCurrentSession()创建的session会绑定到当前的线程中去,保证同一个线程使用的
session是同一个, 而采用openSession()则不会。
2.getCurrentSession()创建的session会在commit或rollback后自动关闭,采用openSession()
则不会。
3.使用getCurrentSession()需再核心配置文件中添加:
<property name="hibernate.current_session_context_class">thread</property>
4.openSession()得到得session可以在显式开启事务的环境中使用,也可以在不开启事务的环
境中使用(只能获取进行查询,其他操作无效);getCurrentSession()必须在显式开启事务环
境中使用。
测试1:openSession在不开启事务的情况下执行操作
Session session= SessionFactoryUtil.openSession();
(1):session.get(UserInfo.class,14L); //执行成功,得到数据
(2):session.delete(new UserInfo(16L)); //执行成功 但数据库数据不变(符合逻辑)
session.close();
追溯了下源码发现:
在不开启事务的情况下,session得到数据库连接是在执行查询语句的时候从连接池中获得。
Java代码
private PreparedStatement getPreparedStatement(
final Connection conn,
String sql,
boolean scrollable,
final boolean useGetGeneratedKeys,
final String[] namedGeneratedKeys,
final ScrollMode scrollMode,
final boolean callable)
在调用这个方法时传入了从连接池中拿到的连接。
在执行完数据操作后调用
afterOperation(boolean success);
发现是非事务型的session直接调用
connectionManager.aggressiveRelease();
释放连接。
测试2:getCurrentSession()在不开启事务的情况下执行操作
Session session= SessionFactoryUtil.getCurrentSession();
(1):session.get(UserInfo.class,14L); //抛出异常get is not valid without active transaction
(2):session.delete(new UserInfo(16L));// 抛出异常get is not valid without active transaction
//session.close(); //线程绑定session会自动关闭
说明: 线程绑定session必须开启事务,此时的session已经加载了拦截器,在执行数据操作时必须在活动的事务范围中。
测试3:openSession在开启事务的情况下执行操作
Session session= SessionFactoryUtil.openSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //执行成功,得到数据
(2):session.delete(new UserInfo(16L)); //执行成功
session.getTransaction().commit();
session.close(); //如若配置hibernate.transaction.auto_close_session=true可省去
分析:
(a):session.getTransaction().begin()-->Transaction result = getTransaction()
-->result.begin()-->jdbcContext.connection()
{
if ( owner.isClosed() ) {
throw new SessionException( "Session is closed" );
}
return connectionManager.getConnection();
}
见到connectionManager有点熟悉了吧,这就是管理数据库连接的连接池.
(b):session.getTransaction().commit()-->connectionManager.aggressiveRelease() 释放连接。
此时的数据库连接是在准备开启事务的时获得,事务提交的时候释放连接。
测试4:getCurrentSession()在开启事务的情况下执行操作
Session session= SessionFactoryUtil.getCurrentSession();
session.getTransaction().begin();
(1):session.get(UserInfo.class,14L); //执行成功
(2):session.delete(new UserInfo(16L)); //执行成功
session.getTransaction().commit();
说明: 线程绑定session已经加载了拦截器,提交的时候释放连接关闭session。
5.openSession()是否显式开启事务决定了session得到连接的时机不同。不开启事务的情况下数
据库连接是在创建 Statement时获得。因此在配置二级缓存的情况get()对象时,如果二级缓存
中有需要的对象时,不会占用数据库连接。相反开启事务的情况下,无论二级缓存中是否有对
象,都会占用数据库连接。
6.this.getsession和this.getHibernateTemplate().getSessionFactory().getCurrentSession()/OpenSession
这两者都是在hibernate与Spring整合时,dao继承的HibernateDaoSupport,这样的确能够提高开发效率 ,
但是不够灵活,而且使DAO层依赖于spring的api,增加了耦合。但是不考虑复用的话还可以。
this.getsession:父类的方法,使用spring管理hibernate的SessionFactory的时候,这个方法会从session
池中拿出一session.这样做有可能有问题,就是超session池连接数的时候,spring无法自动关闭session。
不推荐使用。
其二者: 从spring管理的sessionFactory中创建一个绑定线程的session.spring会根据该线程的执行情况
来自动判断是关闭session还是延迟关闭。这样做可以避免手动的管理事务,同时一个线程最多开启和关
闭一次session又可以提高程序的性能。 极力推荐使用这种方法。
其三者:此session不是线程绑定的。当执行完一个实务的时候自动关闭session.这种方法不用手动管理实
务,但是同一个线程多次的开启和关闭session,浪费系统资源和影响执行效率,正常情况下还是不要用了。