参考博客:https://www.cnblogs.com/Java-web-wy/p/6533672.html
一,Hibernate是什么
Hibernate是一种ORM(Object/Relationship Mapping)框架,它是对象关系映射的持久层框架,它提供了JDBC的轻量级封装.
二,为什么要用Hibernate
在不使用持久层框架的情况下,我们会自己写数据库工具来创建数据库连接,调用连接和相关接口来写操作数据的方法,每个原型都要写一个CRUD方法,冗长又繁杂.
三,Hibernate的组成
1.Hibernate的配置文件
(1)hibernate.cfg.xml 通常放在src文件夹
这个配置文件由三个部分组成, 第一部分是连接数据库的信息, 第二部分是持久化类的映射文件, 第三部分是hibernate框架的相关信息,比如是否显示sql语句,使用了哪些插件信息
<?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> <!-- Database connection settings --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8</property> <property name="connection.username">root</property> <property name="connection.password">admin</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="current_session_context_class">thread</property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <!-- Mapping --> <mapping resource="com/test/pojo/Product.hbm.xml"/> <mapping resource="com/test/pojo/Category.hbm.xml"/> <mapping resource="com/test/pojo/User.hbm.xml"/> </session-factory> </hibernate-configuration>
(2) xxx.cfg.xml
这个文件用于配置映射的类的相关信息, 要将它放在类文件的统一文件夹中
<hibernate-mapping package="com.test.pojo">
<!-- 映射的类和其对应的表 --> <class name="User" table="user_">
<!-- 主键和其增长策略 --> <id name="id" column="id"> <generator class="native"> </generator> </id>
<!-- 其他基本类型属性 --> <property name="name" />
<!-- 这是一个集合属性和其相关信息,包括表名,对应外键和多对多关系 --> <set name="products" lazy="true" table="user_product"> <key column="uid"/> <many-to-many column="pid" class="Product"/> </set> </class> </hibernate-mapping>
2.核心接口
(1)Configuration: 负责配置并启动hibernate,创建SessionFactory, 管理对象关系映射文件,管理hibernate配置信息
(2)SessionFactory:负责初始化hibernate,创建session对象
SessionFactory用于创建Session. 通过相关插件可以将信息二级缓存到SessionFactory中, 这样就避免了不同的Session在获取同一信息时都需要执行一次数据库访问, 而是在第一次获取了信息后, 其他Session直接从SessionFactory中获取信息.
(3)Session:负责被持久化对象CRUD操作,得到了一个session,相当于打开了一次数据库的连接,在hibernate中,对数据的crud操作都是由session来完成, 但如果其中一个操作无法完成,其他操作也不会执行.
Session, 当我们获取了一个对象信息, 并将它保存到Session中时, 这个数据还是瞬时状态, 会随着Session的关闭而消失, 当我们将Session中的信息传递到数据库后, 这个数据会变为持久状态, 也就是随时可以从数据库中获取而不会随着Session的关闭而消失. Session代表着寄给数据库的信件, 将你要做的操作和要提交的信息写在Session中, 最后信息保存到了数据库中, 信件会被销毁. 而从数据库中获得的信息也会保存到Session中, 随时可以获取, 直到Session关闭
SessionFactory sf = new Configuration().configure().buildSessionFactory(); Session s = sf.openSession(); s.beginTransaction(); Product p = new Product(); p.setName("蓝猫"); p.setPrice(200); s.save(p); s.getTransaction().commit(); s.close(); sf.close();
(4)Transaction:负责事务相关的操作, hibernate中的事务默认不是自动提交的, 只有产生了连接,才能进行事务的操作。所以只有有了session以后,才能有transaction
在Hibernate , 任何数据操作都应该放在事务中 , 一个事务由beginTransaction()开始, 由getTransaction().commit()结束.
(5)Query: 负责执行各种数据库查询,Hibernate有面向对象的数据库查询语句,HQL. 通过它可以自定义查询语句.
Query q = s.createQuery("from Product where name like :name"); q.setParameter("name","%"+name+"%"); List list = q.list(); System.out.println(list);
也依然可以使用SQL语句查询,但是操作就更困难,
String name = "i"; String sql = "select * from product_ where name like ‘%"+name+"%‘"; NativeQuery q = s.createSQLQuery(sql); List<Object[]> list = q.list(); //每一个对象都成为了一个Object数组,其属性就是一个Object for (Object[] os : list) { for (Object o: os) { System.out.print(o+"\t"); } System.out.println(); }
四. 各种概念
1.Criteria : 好像在5.x版本被弃用
使用Criteria进行数据查询,与HQL和SQL的区别是Criteria 完全是 面向对象的方式在进行数据查询,将不再看到有sql语句的痕迹,而HQL还有一点痕迹
Criteria c = s.createCriteria(Product.class); //这个方法已过时 c.add(Restrictions.like("name","%"+name+"%")); List<Product> lp = c.list(); System.out.println(lp);
同时可以用Criteria 实现各种分页效果
Criteria c = s.createCriteria(Product.class); c.setFirstResult(2); c.setMaxResults(5);
2.Session的get和load操作 : 两种操作都是从数据库获得数据,但是区别在于
get() : 这个方法一调用,就调用sql语句获取对象属性, 无论是否用到这个对象 对象不存在时返回null
load(): 是一种懒加载方法, 只有在使用到这个对象的属性时,才会调用sql获取对象属性 对象不存在时抛出异常
Product p = (Product) s.get(Product.class, 1); Product p2 = (Product) s.load(Product.class, 2);
3.关系延迟加载:
关系延迟加载需要在配置文件中设置延迟信息:
<set name="products" lazy="true"> <key column="cid" not-null="false" /> <one-to-many class="Product" /> </set>
当两个类具有多对多,一对多关系时,可以使用延迟加载,避免在创建对象后,就加载其关联的对象的信息, 占用一定的空间和时间.
只有在访问到这个属性时,才会调用sql获取其信息.
4.级联: 有四种类型,一般用在一对多, 多对多关系上
all:所有操作都执行级联操作;
none:所有操作都不执行级联操作;
delete:删除时执行级联操作;
save-update:保存和更新时执行级联操作;
如果不使用级联, 在删除某一对象后,其有关联的表也只会将外键设置为空
5.一级缓存和二级缓存:
一级缓存: 当使用Session从数据库获得某一对象信息后, 该对象会被保存在Session中, 在之后需要的时候直接获取,而不需要再次调用sql语句从数据库中获取, 该对象会被保存直到Session被关闭
二级缓存: 添加特定插件后,Hibernate可以将获取的信息保存到SessionFactory中, 在SessionFactory与所有Session共享数据, 也就是如果由某一Session获取一个对象后,在其它Session想要获取同一对象时,不需要再调用sql获取,而是直接从SessionFactory中获取该对象.
SessionFactory sf = new Configuration().configure().buildSessionFactory(); Session s1 = sf.openSession(); s1.beginTransaction(); s1.get(Product.class,8); System.out.println("获取目标,保存到会话1"); s1.get(Product.class,8); System.out.println("再次从会话1获取目标,查看是否有一级缓存"); s1.getTransaction().commit(); Session s2 = sf.openSession(); s2.beginTransaction(); s2.get(Product.class,8); System.out.println("获取目标,保存到会话2"); s2.getTransaction().commit(); //关闭会话 s1.close(); s2.close(); sf.close();
6.两种获取Session的方式: openSession和getCurrentSession
他们的区别是, openSession每次会得到一个新的Session对象
getCurrentSession则和线程有关,同一线程获得同一Session,不同线程获得不同Session
SessionFactory sf = new Configuration().configure().buildSessionFactory(); //同一线程下获取Session Session s1 = sf.getCurrentSession(); Session s2 = sf.getCurrentSession(); System.out.println(s1==s2); s1.close();
static Session s1; static Session s2; Thread t1 = new Thread(){ @Override public void run() { s1 = sf.getCurrentSession(); } }; t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { s2 = sf.getCurrentSession(); } }); t2.start(); t1.join(); t2.join(); System.out.println(s1 == s2);
另外openSession查询可以不需要事务,直接调用get(), save() , delete() 方法即可
而getCurrentSession所有操作必须放在事务中,否则会抛出异常. 同时getCurrentSession在提交事务后,Session会自动关闭
7.Query的list和iterator方法
8.乐观锁来处理脏数据
<version name="version" column="ver" type="int"></version>
通过增加version字段,用于版本信息控制, 防止在两个会话获取同一数据并修改后提交,形成脏数据.
原文:https://www.cnblogs.com/wqq-blog/p/10638262.html