作者:叁念
package com.sannian.utils;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
// 会话工厂,以单例方式管理
private static SessionFactory sessionFactory;
// 以单例方式管理sessionFactory
static {
try {
sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
} catch (HibernateException e) {
e.printStackTrace();
throw new HibernateException("初始化会话工厂失败!");
}
}
// 得到一个单例的会话工厂
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// 获取一个新session
public static Session openSession() {
return sessionFactory.openSession();
}
//获取一个线程绑定的session
public static Session getCurrentSession() throws HibernateException {
return sessionFactory.getCurrentSession();
}
}
顾名思义,指的就是数据库中表的主键是由何种策略产生的
XXX.hbm.xml文件中
<generator class="native">generator>
Session session = HibernateUtil.openSession();//使用上文的自定义工具类获取Session
Transaction transaction = session.beginTransaction();
Customer c = new Customer();// 瞬时态,没有id的,跟session没有关联
c.setCust_name("腾讯");
session.save(c); // 持久态,有id,跟session有关联
transaction.commit(); // 托管|游离态,有id,跟session没有关联
session.close();
以下是相关的图解,结合以上代码不难理解三种状态是如何进行转化的:
那么处于持久态的对象有何作用呢?聪明的伙伴应该就明白了——我对这个对象操作就可以对数据库进行操作了啊
Session session = HibernateUtil.openSession();
Transaction transaction = session.beginTransaction();
Customer newcustomer = session.get(Customer.class, (long)1);
newcustomer.setCust_name("我现在是持久态了,现在我修改了名字,你去看看数据库有没有变化吧");//设置该对象属性对应的值后,无需再书写额外的代码,就会同步到数据库表当中去哦,这就是面向对象操控数据库表
transaction.commit();
session.close();
缓存用于提高效率,这里不过多解释
hibernate中的一级缓存也是为了提高操作数据库的效率.
//HibernateUtil上文提到的工具类
Session session = HibernateUtil.openSession();
Customer customer = session.get(Customer.class, (long)1);
执行如下代码,控制台会出现以下信息,即查询数据库的sql语句信息
为了验证缓存是否存在,我们执行以下代码:
//HibernateUtil上文提到的工具类
Session session = HibernateUtil.openSession();
Customer customer = session.get(Customer.class, (long)1);
System.out.println(customer); //打印结果:Customer [cust_id=1, cust_name=我现在是持久态了,现在我修改了名字,你去看看数据库有没有变化吧。。。
customer.setCust_name("又一次改名");
System.out.println(customer);//打印结果:Customer [cust_id=1, cust_name=又一次改名,
Customer customer1 = session.get(Customer.class, (long)1);
System.out.println(customer1);//打印结果:Customer [cust_id=1, cust_name=又一次改名,
Customer customer2 = session.get(Customer.class, (long)1);
Customer customer3 = session.get(Customer.class, (long)1);
Customer customer4 = session.get(Customer.class, (long)1);
再次查看控制台,查看有几条sql语句?你会发现,咦?似乎还是一条,但是数据都查出来了,这是为什么呢?原因就是hibernate提供了缓存机制,同一个对象的重复查询是不需要重置执行sql语句的,hibernate帮我们减少了不必要的sql语句发送
什么是事务?网上好多人都会举例子,比如银行存钱啊上面的,其实都很老套了,可能大家都明白事务是什么。
但我自己总结的事务其实就是一句话:它是用来保证数据的一致性和完整性的
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。
例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money+100 where name=’B’; (此时A通知B)
update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第
二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现
钱其实并没有转。
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取
该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是
读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。
但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改
为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。
而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就
好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的
都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
事务的隔离级别——级别越高,执行效率就越低
如何在hibernate中指定数据库的隔离级别?(hibernate.cfg.xml文件中配置如下:)
<property name="hibernate.connection.isolation">4property>
在项目中如何管理事务?【重要】
【注意1】: 调用getCurrentSession方法必须配合主配置(hibernate.cfg.xml文件中配置如下:)中的一段配置
<property name="hibernate.current_session_context_class">threadproperty>
如果你没有添加以上配置,项目会出错,如下信息:
org.hibernate.HibernateException: No CurrentSessionContext configured!
【注意2】:通过getCurrentSession方法获得的session对象.当事务提交时,session会自动关闭.不要手动调用close关闭.
sessionFactory.getCurrentSession();