Hibernate框架
一、什么是hibernate?
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。
-----------360百科
确切的说,hibernate其实就是个ORM(Object Relational Mapping)框架,程序员通过操作对象的方式来操作数据库表的记录。
二、快速入门
1.从hibernate官网下载hibernate所需要的jar包
2.搭建环境
1) 将下载好的 jar包中lib\required的所有jar包导入web工程下的lib文件夹,这些是部署框架的核心jar包
2) 导入用于连接数据库的驱动jar包
3) 导入日志jar包(如log4j)
3.编写相对应的持久化类,并生成相对应的set/get,toString方法
/** * javaBean+属于他的映射文件=持久化类 * @author Administrator * */ public class Customer { //注意:这里的数据类型使用包装类,默认值为null private Long cust_id; private String cust_name; private Long cust_user_id; private Long cust_create_id; private String cust_source; private String cust_industry; private String cust_level; private String cust_linkman; private String cust_phone; private String cust_mobile; //省略set/get方法 }
4.在JavaBean所在的包下创建映射的配置文件(默认放在javabean同包下)
1)* 默认的命名规则为:实体类名.hbm.xml
2)* 在xml配置文件中引入约束(引入的是hibernate3.0的dtd约束,不要引入4的约束)
位置:(在hibernate-core-5.0.7.Final.jar\hibernate-core-5.0.7.Final.jar\org.hibernate\hibernate-configuration-3.0.dtd)
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
3) *写相对应的映射,此是与数据库进行映射
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- 配置类和表结构的映射 --> <class name="com.heima.domain.Customer" table="cst_customer"> <!-- 配置主键 见到name属性,JavaBean的属性 见到column属性,是表结构的字段 --> <id name="cust_id" column="cust_id"> <!-- 主键生成策略 --> <generator class="native"/> </id> <!-- 配置其他的属性 --> <property name="cust_name" column="cust_name"/> <property name="cust_user_id" column="cust_user_id"/> <property name="cust_create_id" column="cust_create_id"/> <property name="cust_source" column="cust_source"/> <property name="cust_industry" column="cust_industry"/> <property name="cust_level" column="cust_level"/> <property name="cust_linkman" column="cust_linkman"/> <property name="cust_phone" column="cust_phone"/> <property name="cust_mobile" column="cust_mobile"/> </class> </hibernate-mapping>
5.编写Hibernate核心的配置文件
1) 在src目录下,创建名称为hibernate.cfg.xml的配置文件
2)在XML中引入DTD约束,位置:(在hibernate-core-5.0.7.Final.jar\hibernate-core-5.0.7.Final.jar\org.hibernate\hibernate-configuration-3.0.dtd<?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> <!-- 记住:先配置sessionFactory标签,一个数据库对应一个sessionFactory标签--> <session-factory> <!-- 必须配置的参数,4大参数,数据库的方言 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://192.168.174.130:3306/hibernate_day01</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <!-- 数据库的方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> <!-- 可选配置 --> <!--显示SQL语句,在控制台显示 --> <property name="hibernate.show_sql">true</property> <!--格式化SQL语句,是的显示语句更美观 --> <property name="hibernate.format_sql">true</property> <!-- 开启绑定本地的session --> <property name="hibernate.current_session_context_class">thread</property> <!-- 生成数据库的表结构 慎用create:会先删除原有的表结构,然后再生成一个新的 update:有则再原有基础上增加数据,没有则先创建再添加数据 --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 映射配置文件 ,需要映入映射的配置文件--> <mapping resource="com/heima/domain/Customer.hbm.xml"/> </session-factory> </hibernate-configuration>
6.编写测试
/** * 测试Hibernate框架 * @author Administrator * */ public class Demo1 { /** * 测试保存用户 */ @Test public void testSave1(){ /** * 1.先加载配置文件 * 2.创建sessionFactory对象,生成Session对象(会话) * 3.开启事务 * 5.编写保存的代码 * 6.提交事务 * 7.释放资源 */ //1.先加载配置文件 Configuration config=new Configuration(); //默认加载src目录下hibenate.cfg.xml的配置文件 config.configure(); //创建sessionFactory对象 SessionFactory factory=config.buildSessionFactory(); //创建session对象 Session session=factory.openSession(); //开启事务 Transaction tr=session.beginTransaction(); //编写保存的代码 Customer c=new Customer(); //c.setCust_id(cust_id); 主键是自动递增,不需要自己设置 c.setCust_name("测试3"); c.setCust_level("2"); c.setCust_phone("110"); //保存数据,操作对象就相当于操作数据库的表结构 session.save(c); //提交事务 tr.commit(); //释放资源 session.close(); factory.close(); }
}
其中:
1. Configuration类
* Configuration对象用于配置并且启动Hibernate。
* Hibernate应用通过该对象来获得对象-关系映射文件中的元数据,以及动态配置Hibernate的属性,然后创建SessionFactory对象。
2.SessionFactory
*它是工厂类,是生成Session对象的工厂类
*SessionFactory对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存。
三、代码优化
1.基于每次进行数据处理时都需要调用session,可以将它抽取出来,作为一个公共类
绑定本地的Session
1.现在的Hibernate框架中,使用session对象开启事务,所以需要来传递session对象,框架提供了ThreadLocal的方式
* 需要在hibernate.cfg.xml的配置文件中提供配置
* <property name="hibernate.current_session_context_class">thread</property> <!--(注意:放在mapping标签之前)-->
* 使用SessionFactory的getCurrentSession()方法,获取当前的Session对象。并且该Session对象不用手动关闭,线程结束了,会自动关闭。
public static Session getCurrentSession(){ return factory.getCurrentSession(); }
* 注意:想使用getCurrentSession()方法,必须要先配置才能使用。
package com.itheima.utils; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * Hibernate框架的工具类 * @author Mr_佳先森 * */ public class HibernateUtils { //ctrl+shift+x将小写字母变成大写,用于常量 private static final Configuration CONFIG; private static final SessionFactory FACTORY; static{ CONFIG=new Configuration().configure(); FACTORY=CONFIG.buildSessionFactory(); } /** * 从构造工厂中获取sesson对象 * openSession:作为一级缓存,可以提升查询数据效率,但是当session生命周期 * 结束,程序不可从缓存中获取数据 */ public static Session getSession(){ return FACTORY.openSession(); } /** * getCurrentSession():将session封装ThreadLocal中,每个线程调用线程不受 * 其他线程的影响,即达到线程安全,又避免了悲观锁的效率低下的问题(即使用乐观锁) * 需要在核心配置文件中添加 * @return */ public static Session getCurrentSession(){ return FACTORY.getCurrentSession(); } public static void main(String[] args) { getSession(); } }
其中session接口
1.Session是在Hibernate中使用最频繁的接口。也被称之为持久化管理器。它提供了和持久化有关的操作,比如添加、修改、删除、加载和查询实体对象
2.Session是线程不安全的
3.Session有一个缓存,被称之为Hibernate的一级缓存。每个Session实例都有自己的缓存
4.session常用的方法:
save() delete() get() update() save() createQuery()
2.调用工具类
/** * 测试Hibernate框架 * @author Administrator * */ public class Demo1 { /** * 测试工具类 */ @Test public void testSave2(){ Session session=HibernateUtils.getSession(); //开启事务 Transaction tr=session.beginTransaction(); //编写保存的代码 Customer c=new Customer(); //c.setCust_id(cust_id); 主键是自动递增,不需要自己设置 c.setCust_name("美美"); c.setCust_level("2"); c.setCust_phone("120"); //保存数据,操作对象就相当于操作数据库的表结构 session.save(c); //提交事务 tr.commit(); //释放资源 session.close(); } /** * 测试查询方法,通过主键来查询一条记录 */ @Test public void testGet(){ Session session=HibernateUtils.getSession(); //这里因为是查询事务,所以无需要是事务 //Transaction tr=session.beginTransaction(); //这里因为主键是Long类型,所以数字后面要加个L Customer coustomer=session.get(Customer.class, 2L); System.out.println(coustomer); //tr.commit(); session.close(); } /** * 测试删除的方法 * 注意:删除或者修改之前,要先查询在删除或者修改 */ @Test public void testDel(){ Session session=HibernateUtils.getSession(); Transaction tr=session.beginTransaction(); Customer c=session.get(Customer.class,2L); session.delete(c); tr.commit(); session.close(); } /** * 测试修改的方法 */ @Test public void testUpdate(){ Session session=HibernateUtils.getSession(); Transaction tr=session.beginTransaction(); Customer c=session.get(Customer.class,3L); c.setCust_name("小苍"); c.setCust_level("3"); session.update(c); tr.commit(); session.close(); } /** *添加或者修改 */ @Test public void testSaveOrUpdate(){ Session session=HibernateUtils.getSession(); Transaction tr=session.beginTransaction(); //Customer c=new Customer(); //注意:这里的id值不能自己设置,否则会报错,因为他是由框架管理 //c.setCust_id(4L); //注意:查询的id必须存在,否则会报空指针异常 Customer c=session.get(Customer.class,3L); c.setCust_name("小菜"); session.saveOrUpdate(c); tr.commit(); session.close(); } /** * 测试一个查询的方法 */ @Test public void testSel(){ Session session=HibernateUtils.getSession(); Transaction tr=session.beginTransaction(); //创建一个查询的接口 Query query=session.createQuery("from Customer"); //查询所有的数据select * from 表名 List<Customer> list=query.list(); for(Customer c:list){ System.out.println(c); } tr.commit(); session.close(); } /** * 测试Hibernate框架正规写法 */ @Test public void testSave3(){ Session session=null; Transaction tr=null; try{ session=HibernateUtils.getSession(); tr=session.beginTransaction(); Customer c=new Customer(); c.setCust_name("小强"); session.save(c); tr.commit(); }catch(Exception e){ tr.rollback(); e.printStackTrace(); }finally{ session.close(); } } }
四、Hibernate的缓存
1.Hibernate框架提供了两种缓存
* 一级缓存 -- 自带的不可卸载的.一级缓存的生命周期与session一致.一级缓存称为session级别的缓存.
* 二级缓存 -- 默认没有开启,需要手动配置才可以使用的.二级缓存可以在多个session中共享数据,二级缓存称为是sessionFactory级别的缓存.
2.Session对象的缓存概述
* Session接口中,有一系列的java的集合,这些java集合构成了Session级别的缓存(一级缓存).将对象存入到一级缓存中,session没有结束生命周期,那么对象在session中存放 着
* 内存中包含Session实例 --> Session的缓存(一些集合) --> 集合中包含的是缓存对象!
3.测试一级缓存存在
/** * 证明一级缓存存在 */ @Test public void run2(){ Session session=HibernateUtils.getSession(); Transaction tr=session.beginTransaction(); User user=new User(); user.setName("小明"); user.setAge(20); //保存用户 Serializable id=session.save(user); System.out.println(id); //获取对象,不会看到Sql语句 User user2=session.get(User.class,id); System.out.println(user2.getName()); tr.commit(); session.close(); }
五、Hibernate之事务
1.什么是事务
事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.
2. 事务的特性
* 原子性 -- 事务不可分割.
* 一致性 -- 事务执行的前后数据的完整性保持一致.
* 隔离性 -- 一个事务执行的过程中,不应该受到其他的事务的干扰.
* 持久性 -- 事务一旦提交,数据就永久保持到数据库中.
3.关于解决数据丢失更新问题
数据当涉及到并发访问时,第一想到的是添加锁机制,java中Thread 有添加synchronized关键字,数据库中也有添加锁的机制
1)悲观锁
即在数据库语句中添加"for update"字句。当A事务在操作该条记录时,会把该条记录锁起来,其他事务是不能操作这条记录的,只有当A事务提交后,锁释放了,其他 事务才能操作该条记录
2)乐观锁
在表结构中添加version字段(属性),默认值为0。当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时 会更新版本号version=1;当B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误。
3)锁使用方法
悲观锁:
session.get(Customer.class, 1,LockMode.UPGRADE);
乐观锁:
1)) 持久化类
public class User { private Integer id; private String name; private Integer age; //在javabean中添加属性(乐观锁) private Integer version; //省略set/get toString()方法 }
2)) 持久化类映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.itheima.domain.User" table="t_user"> <id name="id" column="id"> <!-- increment:获取主键的最大值,进行+1,作为主键 缺点:不适合并发访问 --> <generator class="increment"></generator> </id> <!-- 乐观锁 ,就添加乐观锁的机制--> <version name="version"/> <property name="name" column="name" length="30"/> <property name="age" column="age"/> </class> </hibernate-mapping>
3)) 此时可以写两个测试查询的方法,进行debug调试
关于version,当左边更改数据时,发现自己的版本(0)与数据库的版本(1)不一致,说明自己不是最新的版本,会放弃此次操作
六、hibernate的几种查询方式(简述)
/** * 测试查询 * @author Administrator * */ public class Demo4 { /** * 测试Query的查询接口 */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询方式 Query query=session.createQuery("from User"); List<User> list=query.list(); for(User user:list){ System.out.println(user); } tr.commit(); session.close(); } /** * 添加查询条件 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询方式HQL(是Hibernate的独有的,操作的是对象) Query query=session.createQuery("from User where age>?"); //写法二:Query query=session.createQuery("from User where age> :aa"); //设置值:注意:这里区别于JDBC(下标为1) query.setInteger(0,15); //query.setInteger("aa",15); List<User> list=query.list(); for(User user:list){ System.out.println(user); } tr.commit(); session.close(); } @Test public void run3(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询方式HQL(是Hibernate的独有的,操作的是对象) Query query=session.createQuery("from User where name like ?"); query.setString(0,"%k%"); List<User> list=query.list(); for(User user:list){ System.out.println(user); } tr.commit(); session.close(); } /** * Criteria接口:条件查询,非常适合 * 完全面对对象,没有太多sql语句 */ @Test public void run4(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //先获取到Criteria接口 Criteria criteria=session.createCriteria(User.class); //没有条件,查询所有的数据 List<User> list=criteria.list(); System.out.println(list); tr.commit(); session.close(); } /** * 按条件查询 */ @Test public void run5(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //先获取到Criteria接口 Criteria criteria=session.createCriteria(User.class); //添加查询条件 //Criterion是Hibnernate提供的条件查询的对象,向传入条件使用的工具类 //Restrictions提供的静态方法,拼接查询条件 criteria.add(Restrictions.gt("age",18));//gt为大于 //继续添加条件 criteria.add(Restrictions.like("name","%s%")); //没有条件,查询所有的数据a List<User> list=criteria.list(); System.out.println(list); tr.commit(); session.close(); } }
七、hibernate之级联处理数据
需求:假设一个客户对应多个联系人,每个客户信息的处理都会牵扯到相对应的联系人;相反,每一个联系人的处理也会牵扯到相对应的客户
1.创建持久化类
1)在客户中添加set集合关联联系人
// 一个客户对应多个联系人:放的是联系人的集合.(Hibernate默认使用的集合是Set集合.集合必须要自己手动初始化) private Set<LinkMan> linkMans = new HashSet<LinkMan>();
2)在联系人中添加客户属性用于关联客户
// 联系人关联的客户对象://这里不要写客户的外键,要编写一个对象,而这个对象千万不能自己new,框架会帮你new private Customer customer;// ORM框架 Object
2.创建相对应的映射文件
1)在客户映射文件中配置关联联系人的标签set
<!-- 配置关联对象 --> <!-- set标签: * name属性:多的一方的集合的属性名称. --> <set name="linkMans"> <!-- key标签 : * column属性:多的一方的外键的名称. --> <key column="lkm_cust_id"></key> <!-- one-to-many标签: * class属性:多的一方的类全路径 --> <one-to-many class="com.clj.domain.LinkMan"/> </set>
2) 在联系人映射文件中添加<many-to-one>标签关联客户
<!-- 配置关联对象: --> <!-- many-to-one:标签.代表多对一. * name :一的一方的对象的名称. * class :一的一方的类的全路径. * column :表中的外键的名称. --> <many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id"/>
3.编写测试类
@Test // 向客户 和 联系人中同时保存数据: public void demo1(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); // 创建一个客户 Customer customer = new Customer(); customer.setCust_name("张总"); // 创建两个联系人: LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("秦助理"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("胡助理"); // 建立关系: customer.getLinkMans().add(linkMan1); customer.getLinkMans().add(linkMan2); linkMan1.setCustomer(customer); linkMan2.setCustomer(customer); session.save(customer); session.save(linkMan1); session.save(linkMan2); tx.commit(); }
八、级联保存
1.保存一个客户的同时保存相对应的联系人
1)在客户映射文件中的<set>标签中添加cascade=”save-update”属性
<set name="linkmans" cascade="save-update">
<!-- 需要出现子标签 -->
<key column="lkm_cust_id"/>
<one-to-many class="com.clj.domain.Linkman"/>
</set>
2)添加测试类
级联是有方向性: * 保存客户的时候级联保存联系人. @Test /** * 测试级联保存: * * 保存客户 同时 级联保存联系人. * 在set集合上配置cascade=”save-update” */ public void demo3(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); // 保存客户: Customer customer = new Customer(); customer.setCust_name("陈总"); // 保存联系人: LinkMan man1 = new LinkMan(); man1.setLkm_name("小花"); // 建立关系: customer.getLinkMans().add(man1); man1.setCustomer(customer); // 执行保存操作: session.save(customer); // TransientObjectException:customer变为持久态对象,man 还是瞬时态对象. // session.save(man1); tx.commit(); }
2.保存联系人的同时保存相对应的客户
1)在联系人映射文件的<one-to-many>标签中添加cascade=”save-update”属性
<many-to-one name="customer" class="com.clj.domain.Customer" column="lkm_cust_id" cascade=”save-update”/>
2) 编写相对应的测试类
@Test /** * 测试级联保存: * * 保存联系人 级联 保存客户. * 在many-to-one上配置cascade=”save-update” */ public void demo4(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); // 保存客户: Customer customer = new Customer(); customer.setCust_name("肖总"); // 保存联系人: LinkMan man1 = new LinkMan(); man1.setLkm_name("小娇"); // 建立关系: customer.getLinkMans().add(man1); man1.setCustomer(customer); // 执行保存操作: // session.save(customer); // TransientObjectException:customer变为持久态对象,man 还是瞬时态对象. session.save(man1); tx.commit(); }
九、级联删除
需求:删除客户的时候同时删除客户的联系人
1)在客户映射文件下的<set>标签中配置cascade=”delete”属性
2 ) 编写相对应的测试类
@Test /** * 测试级联删除 * 删除客户的时候 删除联系人: * 需要在Customer.hbm.xml中set标签上配置cascade="delete" */ public void demo6(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); Customer customer = session.get(Customer.class, 1l); session.delete(customer); // 不能级联删除的. /*Customer customer = new Customer(); customer.setCust_id(1l); session.delete(customer);*/ tx.commit(); }
需求:删除联系人的时候同时删除客户
1)在联系人映射文件下的<one-to-many>标签中配置cascade=”delete”属性
2)编写测试类
@Test /** * 测试级联删除 * 删除联系人 同时删除 客户: * 需要在LinkMan.hbm.xml中many-to-one标签上配置cascade="delete" */ public void demo7(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); LinkMan linkman = session.get(LinkMan.class, 1l); session.delete(linkman); tx.commit(); }
补充:
级联操作时,时常会因为双向关联会产生许多冗余的数据,因为快照机制,在数据处理时进行数据的比对。
此时得用到inverse="true"属性
@Test /** * 更改联系人所属的客户 * * 双向关联 会产生多余的SQL: */ public void demo8(){ Session session = HibernateUtils.getCurrentSession(); Transaction tx = session.beginTransaction(); LinkMan linkman = session.get(LinkMan.class, 5l); Customer customer = session.get(Customer.class, 4l); // 双向关联: linkman.setCustomer(customer); customer.getLinkMans().add(linkman); tx.commit(); }
此时,在客户映射文件中添加inverse="trues"属性,就可避免数据冗余(一的一方放弃主键维护)
<set name="linkmans" cascade="save-update" inverse="true">
<!-- 需要出现子标签 -->
<key column="lkm_cust_id"/>
<one-to-many class="com.clj.domain.Linkman"/>
</set>
十、Hibernate框架查询方式
1.OID检索方式(通过唯一主键进行查询)
语法:session.get(对象名.class,主键Id);
/** * OId的方式查询与对象导航的方式(两者特点:只能查询到一条数据) * 查询客户 */ @Test public void run1(){ //先查询1号客户 Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询1:通过OId的方式查询客户(通过主键查询) //先是有OID的方式查询客户 Customer c=session.get(Customer.class,1L); System.out.println("==================="); //查看该客户联系人的集合 //查询2:对象导航的方式 System.out.println(c.getLinkmans().size()); tr.commit(); }
2.对象导航方式
语法:new User().getRole().getRname()
/** * OId的方式查询与对象导航的方式 * 查询联系人,属于某个客户 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); Linkman man=session.get(Linkman.class,5L); System.out.println("===================="); System.out.println(man.getCustomer().getCust_name()); tr.commit(); }
3.HQL的查询方式
1) HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似
2)HQL 查询语句是面向对象的,Hibernate负责解析HQL查询语句, 然后根据对象-关系映射文件中的映射信息, 把 HQL 查询语句翻译成相应的 SQL 语句.
/** * HQL的检索方式 * @author Administrator * */ public class Demo2 { /** * 基本演示 */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建查询接口 Query query=session.createQuery("from Customer"); //调用list()方法,查询 List<Customer> list=query.list(); for(Customer customer:list){ System.out.println(customer); } tr.commit(); } /** * 支持方法链的编程风格 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建HQL的查询接口 List<Customer> list=session.createQuery("from Customer").list(); for(Customer customer:list){ System.out.println(customer); } tr.commit(); } /** * 使用别名的方式 */ @Test public void run3(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建HQL的查询接口 //注意:这里不能用select * from Customer框架中没有这个语法 List<Customer> list=session.createQuery("select c from Customer c").list(); for(Customer customer:list){ System.out.println(customer); } tr.commit(); } /** * 排序查询 * SQL:order by 字段 asc/desc; * HQL:关键字是一样的,都是有order by 属性 */ @Test public void run4(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询联系人 //注意:这里是order by+属性(不是字段) List<Linkman> list=session.createQuery("from Linkman w order by w.km_id desc").list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * HQL分页查询的两个方法 * setFirstResult(a) --从哪条记录开始,如果查询是从第一条开始,值是0 * setMaxResults(b) --没页查询的记录条数 */ @Test public void run5(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); Query query=session.createQuery("from Linkman"); //分页查询,调用方法,查询第一页的数据1-3条 /*query.setFirstResult(0); query.setMaxResults(3);*/ //查询第二页的数据 query.setFirstResult(3);//计算公式:(当前页-1)*pageSize=3 query.setMaxResults(3); List<Linkman> list=query.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 按条件进行查询 */ @Test public void run6(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //Query query=session.createQuery("from Linkman l where l.lkm_gender=?"); Query query=session.createQuery("from Linkman l where l.lkm_id>? and l.lkm_gender=?"); //传入 //query.setString(0,"男"); //通用符setParameter(Interger,object)无须考虑问号的参数类型 query.setParameter(0,3L); query.setParameter(1,"女"); List<Linkman> list=query.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 按条件进行查询 * 占位符的方式 */ @Test public void run7(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); Query query=session.createQuery("from Linkman l where l.lkm_gender=:gender"); //传入 query.setString("gender","女"); List<Linkman> list=query.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 指定字段查询 */ @Test public void run8(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); Query query=session.createQuery("select lkm_name,lkm_gender from Linkman"); List<Object[]> list=query.list(); for(Object[] objects:list){ System.out.println(Arrays.toString(objects)); } tr.commit(); } /** * 投影查询:只查询几个字段,不是所有的字段 * 第一步:需要在JavaBean类提供对应的构造方法(指定的有参和无参) * 第二步:HQL语句发生变化 */ @Test public void run9(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); Query query=session.createQuery("select new Linkman(lkm_name,lkm_gender) from Linkman"); List<Linkman> list=query.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 聚合函数:count() avg() max() min() */ @Test public void run10(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询所有的联系人的数量 //Number是所有数值类型的父类 List<Number> list=session.createQuery("select count(w) from Linkman w").list(); //通过下标值进行取值 Long count=list.get(0).longValue();//转为long类型 System.out.println("数量为:"+count); tr.commit(); } /** * 聚合函数:求数量 * sum(属性必须为数值类型) */ @Test public void run11(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //查询所有的联系人的数量 //Number是所有数值类型的父类 List<Number> list=session.createQuery("select sum(lkm_id) from Linkman").list(); //通过下标值进行取值 Long count=list.get(0).longValue();//转为long类型 System.out.println("数量为:"+count); tr.commit(); } }
4.QBC检索方式
1)QBC:Query By Criteria 按条件进行查询
2)条件查询的方法:
* * Restrictions.eq -- 相等
* Restrictions.gt -- 大于号
* Restrictions.ge -- 大于等于
* Restrictions.lt -- 小于
* Restrictions.le -- 小于等于
* Restrictions.between -- 在之间
* Restrictions.like -- 模糊查询
* Restrictions.in -- 范围
* Restrictions.and -- 并且
* Restrictions.or -- 或者
3)测试代码
/** * QBC的查询(条件查询) * @author Administrator * */ public class Demo3 { /** * QBC的基本入门查询 */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Customer.class); List<Customer> list=criteria.list(); for(Customer customer:list){ System.out.println(customer); } tr.commit(); } /** * QBC的基本查询 * 排序查询,调用的方法 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //调用排序的方法,addOrder(),这里演示降序排序 criteria.addOrder(Order.desc("lkm_id")); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * QBC分页的方法和HQL分页的方法一样的 */ @Test public void run3(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //调用排序的方法,addOrder(),这里演示降序排序 criteria.addOrder(Order.desc("lkm_id")); //设置分页的方法 criteria.setFirstResult(0); criteria.setMaxResults(3); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * QBC的条件查询 */ @Test public void run4(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //使用方法添加条件 criteria.add(Restrictions.eq("lkm_gender","男")); //ge大于等于 criteria.add(Restrictions.ge("lkm_id",3L)); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * in查询 */ @Test public void run5(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); List<Long> params=new ArrayList<Long>(); params.add(1L); params.add(2L); params.add(3L); //使用in,方法查询(当然,这里不一定弄过集合,可以整个数组也行) criteria.add(Restrictions.in("lkm_id",params)); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * or查询 */ @Test public void run6(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); criteria.add(Restrictions.or(Restrictions.eq("lkm_gender", "女"),Restrictions.gt("lkm_id",3L))); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 判断值是否为空 */ @Test public void run7(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //找所有的lkm_email是空的值 //注意:isEmpty是判断集合是否为空 criteria.add(Restrictions.isNull("lkm_email")); List<Linkman> list=criteria.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } /** * 聚合函数的查询 */ @Test public void run8(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //设置聚合函数的查询方式 List<Number> list=criteria.setProjection(Projections.count("lkm_id")).list(); Long count=list.get(0).longValue(); System.out.println("数量为:"+count); tr.commit(); } /** * 强调问题:select count(*) from 表,又想查select * from 表,存在问题 */ @Test public void run9(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建QBC查询接口 Criteria criteria=session.createCriteria(Linkman.class); //设置聚合函数的查询方式 criteria.setProjection(Projections.count("lkm_id")); List<Number> list=criteria.list(); Long count=list.get(0).longValue(); System.out.println("数量为:"+count); //再设置一遍setprojection方法 criteria.setProjection(null); List<Linkman> mans=criteria.list(); for(Linkman linkman:mans){ System.out.println(linkman); } tr.commit(); } /** * 演示离线条件对象 * 创建条件查询时不需要session * 只有真正涉及到查询数据,调用数据库时才需要用到session */ @Test public void run10(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建离线条件查询的对象 DetachedCriteria criteria=DetachedCriteria.forClass(Linkman.class); //去添加查询条件了 criteria.add(Restrictions.eq("lkm_gender","女")); //查询 List<Linkman> list=criteria.getExecutableCriteria(session).list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } }
5.SQL查询方式
public class Demo4 { /** * 测试SQL语句的查询 */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建的是SQL的查询的接口 SQLQuery query=session.createSQLQuery("select * from cst_linkman"); //查询数据(注意:这里泛型是Object,不是对象,因为这里返回的数据时表的数据,不是对象) List<Object[]> list=query.list(); for(Object[] object:list){ System.out.println(Arrays.toString(object)); } tr.commit(); } /** * 把数据封装到对象中 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //创建的是SQL的查询的接口 SQLQuery query=session.createSQLQuery("select * from cst_linkman"); //通过方法设置 query.addEntity(Linkman.class); List<Linkman> list=query.list(); for(Linkman linkman:list){ System.out.println(linkman); } tr.commit(); } }
6.HQL多表查询
/** * HQL的多表查询 * @author Administrator * */ public class Demo5 { /** * 查询的客户,客户和联系人有关联 * select * from cst_customer c,cst_linkman l when c.id=l.id; */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //内连接的查询 //这里的linkmans关联的是Customer类中集合属性名 Query query=session.createQuery("from Customer c inner join c.linkmans"); //这里默认放回值是数组 List<Object[]> list=query.list(); for(Object[] obj:list){ System.out.println(Arrays.toString(obj)); } tr.commit(); } /** * 数据默认返回的数组,把数据封装到对象中 * 提供关键字:fetch 迫切连接 * 缺点:数据有冗余,有重复数据 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //内连接的查询 //这里的linkmans关联的是Customer类中集合属性名 Query query=session.createQuery("from Customer c inner join fetch c.linkmans"); //这里默认放回值是数组 List<Customer> list=query.list(); for(Customer customer:list){ System.out.println(customer); } tr.commit(); } /** * 解决数据的重复的问题 */ @Test public void run3(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //内连接的查询 Query query=session.createQuery("from Customer c inner join fetch c.linkmans"); List<Customer> list=query.list(); //手动解决,编程中都是用这种方式解决重复的问题 Set<Customer> set=new HashSet<Customer>(list); for(Customer customer:set){ System.out.println(customer); } tr.commit(); } }
十一、Hibernate之延迟加载
1.什么是延迟加载?
延迟加载先获取到代理对象,当真正使用到该对象中的属性的时候,才会发送SQL语句,是Hibernate框架提升性能的方式
2.Session对象的load方法默认就是延迟加载
3.hibernate框架默认形式就是延迟加载,如果想取消此功能,需添加lazy="false"属性
/** * 演示的延迟加载,提升程序的性能 * 即当真正需要数据时才进入数据库查询 * @author Administrator * */ public class Demo6 { /** * 类级别的延迟加载 * 需要使用session.load()默认情况使用的延迟加载 * 只有当查询对象的属性时才调用数据库进行数据的查询 * 默认情况下配置文件中的延迟加载默认值为true(即lazy="true") */ @Test public void run1(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //Customer c1=session.get(Customer.class,1L);//原始在此时就调用数据库 Customer c1=session.load(Customer.class,1L); System.out.println("====================="); System.out.println(c1.getCust_name());//此时才调用数据库查询数据 tr.commit(); } /** * 在调用load方法情况下怎么取消延迟加载 * 1.在配置文件中设置lazy="false" * 2.重新初始化对象 */ @Test public void run2(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //Customer c1=session.get(Customer.class,1L);//原始在此时就调用数据库 Customer c1=session.load(Customer.class,1L); //把c1对象初始化 Hibernate.initialize(c1); System.out.println("====================="); System.out.println(c1.getCust_name());//此时才调用数据库查询数据 tr.commit(); } /** * 关联级别的延迟加载 * 说的是客户下的联系人的集合 */ @Test public void run3(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); //先查询1号客户 Customer c1=session.get(Customer.class,1L);//默认情况下是延迟加载,此时只查询客户,不会查询联系人 System.out.println("================="); //看客户下所有的联系人 System.out.println("联系人"+c1.getLinkmans().size()); tr.commit(); } /** * fetch属性能解决的问题 */ @Test public void run4(){ Session session=HibernateUtils.getCurrentSession(); Transaction tr=session.beginTransaction(); List<Customer> list=session.createQuery("from Customer").list(); int count=0; for(Customer customer:list){ count++; System.out.println("客户"+count+"的联系人数量为"+customer.getLinkmans().size()); } tr.commit(); } }