hibernate学习笔记

hibernate

hibernate好处:

  • Dao层框架
  • 面向对象的思路操作框架
    操作数据库的时候,可以以面向对象的方式来完成。不需要写SQL语句;

hibernate:搭建

  • 导包
  • 创建数据库
  • 书写orm元数据(对象与表的映射配置文件)
		<?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.rabbit.domain.Customer" table="cst_customer">
		    		<id name="cust_id" column="cust_id">
		    			<generator class="native"></generator>
		    		</id>
		    		<property name="cust_name" column="cust_name"></property>
		    		<property name="cust_source" column="cust_source"></property>
		    		<property name="cust_industyr" column="cust_industyr"></property>
		    		<property name="cust_level" column="cust_level"></property>
		    		<property name="cust_linkman" column="cust_linkman"></property>
		    		<property name="cust_phone" column="cust_phone"></property>
		    		<property name="cust_mobile" column="cust_mobile"></property>
		    	</class>
		    </hibernate-mapping>
  • 书写主配置文件:文件名必须为:hibernate.cfg.xml
		<?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>
					<!-- 
					#hibernate.dialect org.hibernate.dialect.MySQLDialect
					#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
					#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
					#hibernate.connection.driver_class com.mysql.jdbc.Driver
					#hibernate.connection.url jdbc:mysql:///test
					#hibernate.connection.username gavin
					#hibernate.connection.password
					 -->
					<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
					<property name="hibernate.connection.url">jdbc:mysql:///mysqltest?serverTimezone=GMT%2B8</property>
					<property name="hibernate.connection.username">root</property>
					<property name="hibernate.connection.password">admin</property>
					<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
					<!-- #hibernate.show_sql true 
							#hibernate.format_sql true
							
							## auto schema export
		
							#hibernate.hbm2ddl.auto create-drop
							#hibernate.hbm2ddl.auto create
							#hibernate.hbm2ddl.auto update
							#hibernate.hbm2ddl.auto validate
							
					-->
					<property name="hibernate.show_sql">true</property>
					<property name="hibernate.format_sql">true</property>
					<property name="hibernate.hbm2ddl.auto">update</property>
					
					<!-- 写上对象与表的配置文件路劲 -->
					<mapping resource="com/rabbit/domain/Customer.hbm.xml"/>
				</session-factory>
			</hibernate-configuration>
  • 书写代码测试:注意导包不要导错
		import org.hibernate.Session;
		import org.hibernate.SessionFactory;
		import org.hibernate.Transaction;
		import org.hibernate.cfg.Configuration;
		
		public static void main(String[] args){
				Configuration conf = new Configuration().configure();
				
				SessionFactory sf = conf.buildSessionFactory();
				Session session = sf.openSession();
				
				Transaction tx = session.beginTransaction();
				
				Customer c = new Customer();
				c.setCust_name("百度公司");
				session.save(c);//执行保存
				
				tx.commit();
				session.close();
				sf.close();
				
			}


配置文件详解

Orm元数局配置文件:

	
	
		<?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">
		    <!-- package 属性 填写一个包名,写了包名之后,需要填写完整类名的可以直接写简单类名 -->
		    <hibernate-mapping package="com.rabbit.domain">
		    
		    	<!-- 
		    		Class元素:配置实体与表的对应关系
		    			name:完整类名
		    			table:数据库表名
		    	 -->
		    	<class name="Customer" table="cst_customer">
		    		<!-- id元素:配置主键映射的属性
		    				name :填写主键对应的属性名
		    				column:填写主键中的主键列名
		    		 -->
		    		<id name="cust_id" column="cust_id">
							<!-- generator:主键生成策略,就是每条记录录入时,主键的生成规则
    							identity:主键自增,由数据库来维护,录入时不需要指定主键
    							increment:(不推荐使用,increment存在线程安全问题,并发访问时会出现两个主键相同的情况)主键自增,由hibernate来维护,每次插入前会先查询表中id最大值,+1作为新主键值;
    							sequence:Oracle中的主键生成策略
    							hilo(不使用):高底位算法,主键自增,由hibernate来维护
    							native(推荐使用):hilo+sequence+identity;自动三个选一个策略
    							uuid:用来产生一个理论上永远不会重复的随机字符串作为主键
    							assigned:自然主键生成策略
    			 		-->
		    			<generator class="native"></generator>
		    		</id>
		    		<!-- property配置除id之外的普通属性映射
		    				name:对应属性名
		    				column(可选):对应的表列名,默认值:默认使用name属性的值
		    				type(可选,尽量别填):填写该列(属性)的类型,如果不填,hibernate会自动检测实体的属性
		    		 					每个类型有三种填发:java  hibernate  sql
		    		 		not-null:配置该属性是否不能为空,默认值是false;
		    		 		length(可选):配置数据库该列的长度,默认值:会使用数据库类型的最大长度
		    		 -->
		    		<property name="cust_name" column="cust_name"></property>
		    		<property name="cust_source" column="cust_source"></property>
		    		<property name="cust_industyr" column="cust_industyr"></property>
		    		<property name="cust_level" column="cust_level"></property>
		    		<property name="cust_linkman" column="cust_linkman"></property>
		    		<property name="cust_phone" column="cust_phone"></property>
		    		<property name="cust_mobile" column="cust_mobile"></property>
		    	</class>
		    </hibernate-mapping>

书写主配置文件:文件名必须为:hibernate.cfg.xml:

		<?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>
					<!-- 
					#hibernate.dialect org.hibernate.dialect.MySQLDialect
					#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
					#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
					#hibernate.connection.driver_class com.mysql.jdbc.Driver
					#hibernate.connection.url jdbc:mysql:///test
					#hibernate.connection.username gavin
					#hibernate.connection.password
					 -->
					 
					 <!-- 数据库驱动 -->
					<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
					<!-- 连接数据库url -->
					<property name="hibernate.connection.url">jdbc:mysql:///mysqltest?serverTimezone=GMT%2B8</property>
					<!-- 数据库用户名 -->
					<property name="hibernate.connection.username">root</property>
					<!-- 数据库密码 -->
					<property name="hibernate.connection.password">admin</property>
					<!-- 数据库方言
							在不同的数据库中,sql语法略有区别,指定方言可以让hibernate在生存sql语句时,针对数据库方言实现
					 -->
					<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
					<!-- #hibernate.show_sql true 	打印sql语句
							#hibernate.format_sql true	格式化sql语句
					-->
					<!-- 可选 -->
					<property name="hibernate.show_sql">true</property>
					<property name="hibernate.format_sql">true</property>
					<!-- 
							
							## auto schema export  自动建表
							#hibernate.hbm2ddl.auto create-drop	自动建表,每次框架运行结束会将所有表删除
							#hibernate.hbm2ddl.auto create			自动建表,如果数据库有这个表就直接覆盖以前的表
							#hibernate.hbm2ddl.auto update			(推荐使用)自动生成表,如果已经存在,就不会再生成,如果表有变动会自动更新表,不会删除任何数据
							#hibernate.hbm2ddl.auto validate			校验,任何情况都不会自动生成表,每次启动会校验数据库中表是否正确。校验失败就会抛出异常
					 -->
					<property name="hibernate.hbm2ddl.auto">update</property>
					
					<!-- 引入orm元数据:
							路径书写,填写src下的路劲;
					 -->
					<mapping resource="com/rabbit/domain/Customer.hbm.xml"/>
				</session-factory>
			</hibernate-configuration>

hibernate Api详解

Configuration:配置加载类,用于加载主配置和orm元数据加载

  • 创建:调用空参构造即可

      Configuration conf = new Configuration();
    
  • 指定读取主配置文件;只要配置文件名叫hibernate.cfg.xml,直接空参加载方法(推荐使用)

      Configuration conf = new Configuration().configure();
    

SessionFactory:创建session工厂:用于创建操作数据库核心对象Session对象的工厂;SessionFactory负责保存和使用所有的配置文件,所有它消耗内存资源非常大;SessionFactory属于线程安全的对象设计

  • 保证在web项目中,只创建一个SessionFactory;

  • 创建:通过加载完配置的Configuration的buildSessionFactory()方法生成SessionFactory;

      SessionFactory sf = conf.buildSessionFactory();
    
  • 获取Session对象:

  • 通过SessionFactory的openSession()方法获得一个新的session对象;通过getCurrentSession()方法获得一个与线程绑定的同一个session对象

  • 获得Session

      Session session = sf.openSession();
    

Session:功能: 表达hibernate框架与数据库之间的连接(会话),类似于JDBC的Connection对象;还可以完成对数据库的增删改查操作;是hibernate操作数据的核心对象

  • session获得操作事务的Transaction对象

      session.getTransaction();
    
  • session获得操作事务的Transaction对象并开启

      Transaction tx = session.beginTransaction();
    
  • 增加数据:

      Customer c = new Customer();
      c.setCust_name("阿萨德公司");
      session.save(c);//执行保存
    
  • 查询数据:根据id查询

      Customer customer = session.get(Customer.class, 1L);
    
  • 修改数据:修改id为1的cust_name为Rabbit

      Customer customer = session.get(Customer.class, 1L);
      customer.setCust_name("Rabbit");
      session.update(customer);
    
  • 删除数据:

      Customer customer = session.get(Customer.class, 1L);
      session.delete(customer);
    

Transaction:事务操作

  • 提交事务

      tx.commit();
    
  • 回滚事务

      tx.rollback();
    

向数据库增加数据完整代码:

	package com.rabbit.domain;
	
	
	import org.hibernate.Session;
	import org.hibernate.SessionFactory;
	import org.hibernate.Transaction;
	import org.hibernate.cfg.Configuration;
	
	public class Demo1 {
		public static void main(String[] args){
			Configuration conf = new Configuration().configure();
			
			SessionFactory sf = conf.buildSessionFactory();
			Session session = sf.openSession();
			//sf.getCurrentSession();
			
			Transaction tx = session.beginTransaction();
			
			
			//查询
			//Customer customer = session.get(Customer.class, 1L);//查询id为1的数据
			//修改:修改id为1的cust_name为
			Customer customer = session.get(Customer.class, 1L);
			customer.setCust_name("Rabbit");
			session.update(customer);
			//增加
			Customer c = new Customer();
			c.setCust_name("阿萨德公司");
			session.save(c);//执行保存
			
			tx.commit();
			session.close();
			sf.close();
			
		}
	}
	

hibernate工具类:单例。没有实例化,只能类名.调用

	package com.rabbit.Utils;
	
	import org.hibernate.Session;
	import org.hibernate.SessionFactory;
	import org.hibernate.cfg.Configuration;
	
	final class HibernateUtils {
		private  static SessionFactory sf ;
		static {
			Configuration conf = new Configuration().configure();
			sf=conf.buildSessionFactory();
		}
		
		private HibernateUtils() {
		}
		public static Session openSession() {
			Session session = sf.openSession();
			return session;
		}
		public static Session getCurrentSession() {
			Session session = sf.getCurrentSession();
			return session;
		}
	}

Hibernate中实体规则

实体类创建的注意事项:

  • 持久化类提供无参数构造
  • 需提供属性:成员变量私有,提供共有get/set方法访问;
  • 持久化类中的属性,尽量提供包装类型;
  • 持久化类需要提供oid,与数据库中的主键列对应;(hibernate管理的数据库表必须要有主键)
  • 不要用final 修饰class;
    • hibernate使用cglib代理对象,代理对象是继承被代理对象,如果被final修饰,将无法继承,就无法代理;

主键类型

  • 自然主键(不常用)
    • 表的业务列中,有某业务列符合,必须有,并且不重复的特征时,该列可以作为主键使;
  • 代理主键(常用)
    • 表的业务列中,没有某业务列符合,必须有,并且不重复的热衷时,创建一个没有意义的列作为主键:id;

hibernate中的对象状态

  • 对象分为三种状态:
    • 瞬时状态:没有id,没有与session关联
    • 持久化状态:有id,与session有关联
      • 持久化状态的任何对象,都会自动同步到数据库;
    • 游离/托管状态:有id,没有与session关联

hibernate进阶:一级缓存

  • 缓存:提高效率;hibernate中的一级缓存也是为了提高操作数据库的效率;
  • 提高效率1:提高查询效率
  • 提高效率2:减少不必要的操作,比如:从数据库获取id为1l的对象会获取两个相同的对象,一个放入缓存,一个放入快照,如果最终提交时缓存的对象跟快照的对象相等,就不执行没必要的sql语句;

hibernate中的事务

  • 事务特性:

    1. a原子性
    2. c一致性
    3. i隔离性
    4. d持久性
  • 事务并发问题

    • 1.脏读
    • 2.不可重复读
    • 3.幻|虚读
  • 事务隔离级别

    • 读未提交–123
    • 读已提交–23
    • 可重复读–3::(Mysql)
    • 串行化 —没有问题,效率低

如何在hibernate中指定隔离级别:在主配置文件中

		<!-- 指定hibernate操作数据库时的隔离级别
			1 读未提交
			2 读已提交
			4 可重复读
			8 串行化
		 -->
		 <property name="hibernate.connection.isolation">4</property>

在hibernate中确保使用同一个session对象的问题,hibernate已经帮我们解决了,我们只需要调用SessionFactory的getCurrentSeesion()方法即可获得与线程绑定的session对象;

  1. 注意: 调用getCurrentSession()方法必须在主配置文件中配置
			 <!-- 指定session与当前线程绑定 -->
			 <property name="hibernate.current_session_context_class">thread</property>
  1. 注意:通过getCurrentSession()方法获得的session对象,当事务提交时,session会自动关闭,不要手动调用close关闭资源;

hibernate中的批量查询

HQL查询:多表查询但不复杂时使用

  • hql语句:全部查询:“from Customer”;条件查询:" from Customer where cust_id=?";
  • 条件查询还可以使用命名占位符" from Customer where cust_id = :cust_id" 用query.setParameter(“cust_id”,1l);
  • 代码演示:

		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		//书写hql语句:from domain where domain成员变量
		String hql = " from Customer where cust_id=?";
		//根据hql语句创建查询对象
		Query query = session.createQuery(hql);
		//设置参数:第一个?位置是0;jdbc是从1开始
		query.setParameter(0, 1l);
		//获取查询结果,直接可以返回domain对象,如果是查询多个返回一个List<Customer>;
		Customer c = (Customer) query.uniqueResult();
		System.out.println(c);
		tx.commit();
		session.close();
  • 分页查询:
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		//书写hql语句:from domain where domain成员变量
		String hql = " from Customer";
		Query query = session.createQuery(hql);
		//设置分页信息:从第一页查,查询1条
		query.setFirstResult(0);//类似于limit方法的第一个问号,从哪儿开始查询
		query.setMaxResults(1);//类似于limit的第二个问号,查多少条语句
		List<Customer> c = query.list();
		System.out.println(c);
		tx.commit();
		session.close();

Criteria查询:无语句面向对象查询(常用于单表查询)

  • 基本语法

    	@Test
    	//Criteria查询语法
    	public void fun1() {
    		Session session = HibernateUtils.openSession();
    		
    		Transaction tx = session.beginTransaction();
    		//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
    		//----------执行操作--------------------
    		//查询所有Customer对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		List<Customer> list = criteria.list();
    				
    		System.out.println(list);
    		//--------------------------------------
    		tx.commit();
    		session.close();
    	}
    
* 条件查询

		@Test
		//Criteria条件查询语法
		
		/*
		 * 			>  		gt
		 * 			>=		ge
		 * 			< 			lt
		 * 			<= 		le
		 * 			== 		eq
		 * 			!=			ne
		 * 			in			in
		 * 			between and 		bettween
		 * 			like		like
		 * 			is not null 		isNotNull
		 * 			is null 				isNull
		 * 			or						or
		 * 			and					and
		 */
		public void fun2() {
			Session session = HibernateUtils.openSession();
			
			Transaction tx = session.beginTransaction();
			//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
			//----------执行操作--------------------
			//得到criteria
			Criteria criteria = session.createCriteria(Customer.class);
			//查询id为1的Customer对象
			criteria.add(Restrictions.eq("cust_id", 1l));
			Customer c = (Customer) criteria.uniqueResult();
			System.out.println(c);
			//--------------------------------------
			tx.commit();
			session.close();
		}
  • 分页查询
		@Test
		//Criteria分页查询语法
		public void fun3() {
			Session session = HibernateUtils.openSession();
			
			Transaction tx = session.beginTransaction();
			//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
			//----------执行操作--------------------
			//得到criteria
			Criteria criteria = session.createCriteria(Customer.class);
			//设置分页信息
			criteria.setFirstResult(0);
			criteria.setMaxResults(1);
			List<Customer> list = criteria.list();
			System.out.println(list);
			//--------------------------------------
			tx.commit();
			session.close();
		}
* Criteria查询总记录数语法;
		
		@Test
			//Criteria查询总记录数语法
			public void fun4() {
				Session session = HibernateUtils.openSession();
				
				Transaction tx = session.beginTransaction();
				//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
				//----------执行操作--------------------
				//得到criteria
				Criteria criteria = session.createCriteria(Customer.class);
				//这只查询的聚合函数===>总行数
				criteria.setProjection(Projections.rowCount());
				Long i = (Long) criteria.uniqueResult();
				System.out.println(i);
				//--------------------------------------
				tx.commit();
				session.close();
			}

原生Sql查询:就是以前的sql语句用法(复杂的业务查询)

* 基本查询:

		@Test
		//Sql查询
		public void fun5() {
			Session session = HibernateUtils.openSession();
			
			Transaction tx = session.beginTransaction();
			//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
			//----------执行操作--------------------
			String sql = "select * from cst_customer";
			
			//穿件查询对象
			SQLQuery query =session.createSQLQuery(sql);
			query.addEntity(Customer.class);//把查询的结果封装成Customer对象
			
			List<Customer> list = query.list();
			System.out.println(list);
			/*
			List<Object [] >list = query.list();
			for (Object[] objects : list) {
				System.out.println(Arrays.toString(objects));
			}
			*/
			//--------------------------------------
			tx.commit();
			session.close();
		}
* 条件查询:

		@Test
			//Sql条件查询
			public void fun5() {
				Session session = HibernateUtils.openSession();
				
				Transaction tx = session.beginTransaction();
				//书写hql语句:如果没有第二个Customer,直接可以写" from Customer"
				//----------执行操作--------------------
				String sql = "select * from cst_customer where cust_id=?";
				
				//穿件查询对象
				SQLQuery query =session.createSQLQuery(sql);
				query.setParameter(0, 1l);
				query.addEntity(Customer.class);//把查询的结果封装成Customer对象
				
				List<Customer> list = query.list();
				System.out.println(list);
				/*
				List<Object [] >list = query.list();
				for (Object[] objects : list) {
					System.out.println(Arrays.toString(objects));
				}
				*/
				//--------------------------------------
				tx.commit();
				session.close();
			}
  • 分页查询:跟以前一样

hibernate::1对多|多对1

  • 用客户表跟联系人表来举例
  • 关联表在联系人中使用一个外键cid列来关联
  • 客户实体:private Set<联系人> linkMens;使用set集合在客户表中存储客户联系人;因为set集合可以排序,也可以去重复;
  • 联系人实体:private 客户 Customer;

orm配置文件:

  • 1对多:
		<?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">
		    <!-- package 属性 填写一个包名,写了包名之后,需要填写完整类名的可以直接写简单类名 -->
		 <hibernate-mapping package="com.rabbit.domain">
		    	<class name="Customer" table="cst_customer">
		    		<id name="cust_id" column="cust_id">
		    			<generator class="native"></generator>
		    		</id>
		    		<property name="cust_name" ></property>
		    		<property name="cust_source"></property>
		    		<property name="cust_industyr"></property>
		    		<property name="cust_level" ></property>
		    		<property name="cust_linkman" ></property>
		    		<property name="cust_phone" ></property>
		    		<property name="cust_mobile" ></property>
		    		<!-- 集合,一对多关系,在配置文件中配置 -->
		    			<!-- 集合属性名 -->
		    		<set name="linkmens">
		    		 <!-- 外键列名 -->
		    			<key column="lkm_cust_id"></key>
		    			 <!-- 与我关联的完整类名(因为上面已经指定了包位置,所以这里可以写简单类名) -->
		    			<one-to-many class="LinkMan"/>
		    		</set>
		    	</class>
		    </hibernate-mapping>
  • 多对1:

		<?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">
		    <!-- package 属性 填写一个包名,写了包名之后,需要填写完整类名的可以直接写简单类名 -->
		    <hibernate-mapping package="com.rabbit.domain">
		    	<class name="LinkMan" table="cst_linkman">
		    		<id name="lkm_id">
		    			<generator class="native"></generator>
		    		</id>
		    		<property name="lkm_gender"></property>
		    		<property name="lkm_name"></property>
		    		<property name="lkm_phone" ></property>
		    		<property name="lkm_email" ></property>
		    		<property name="lkm_qq" ></property>
		    		<property name="lkm_mobile" ></property>
		    		<property name="lkm_memo"></property>
		    		<property name="lkm_position"></property>
		    		
		    		<!-- 多对1 column属性值必须完全一样 -->
		    			<!--  name :属性名
		    					column: 外键列名
		    					class:与我关联的对象完整类名
		    			-->
		    		<many-to-one name="customer" column="lkm_cust_id" class="Customer"></many-to-one>
		    	</class>
		    </hibernate-mapping>

1对多,多对1关系操作:

  • 添加客户并给它联系人
	
		public void fun1() {
				Session session = HibernateUtils.openSession();
				
				Transaction tx = session.beginTransaction();
				
				Customer c = new Customer();
				c.setCust_name("Rabbit");
				
				LinkMan lm1 = new LinkMan();
				lm1.setLkm_name("廖凡");
				LinkMan lm2 = new LinkMan();
				lm2.setLkm_name("lwf");
				//1对多关系,客户下有多个联系人
				c.getLinkmens().add(lm1);
				c.getLinkmens().add(lm2);
				//表达多对1,联系人属于哪个客户
				lm1.setCustomer(c);
				lm2.setCustomer(c);
				
				session.save(c);
				session.save(lm1);
				session.save(lm2);
				tx.commit();
				
				session.close();
			}
  • 给已有客户添加联系人
		@Test
			//为客户添加联系人
			public void fun2() {
				Session session = HibernateUtils.openSession();
				
				Transaction tx = session.beginTransaction();
				//操作----------------------------
				//获得要操作的客户对象
				Customer c = session.get(Customer.class, 5l);
				//创建联系人
				LinkMan lm1 = new LinkMan();
				lm1.setLkm_name("李欣");
				c.getLinkmens().add(lm1);
				lm1.setCustomer(c);
				session.save(lm1);
				//------------------------------
				
				tx.commit();
				session.close();
			}
  • 给已有客户删除联系人
		
		@Test
			//为客户删除联系人
			public void fun3() {
				Session session = HibernateUtils.openSession();
				
				Transaction tx = session.beginTransaction();
				//操作----------------------------
				//获得要操作的客户对象
				LinkMan lm = session.get(LinkMan.class, 2l);
				Customer c = session.get(Customer.class, 5l);
				//删除
				c.getLinkmens().remove(lm);
				lm.setCustomer(null);
				//------------------------------
				
				tx.commit();
				session.close();
			}

1对多,多对1关系操作:进阶—级联操作

  • 在Customer的orm配置文件下的set标签添加cascade标签使用级联操作:一般设置为save-update
		<!-- 级联操作cascade
	    						save-update:级联保存更新
	    						delete:级联删除
	    						all:save-update+delete
	    			 -->
	    		<set name="linkmens" cascade="save-update">
	    		 <!-- 外键列名 -->
	    			<key column="lkm_cust_id"></key>
	    			 <!-- 与我关联的完整类名(因为上面已经指定了包位置,所以这里可以写简单类名) -->
	    			<one-to-many class="LinkMan"/>
	    		</set>
  • 配置之后代码演示:简化操作,只要保存c对象,自动将lm对象保存。简化操作

      public void fun1() {
      	Session session = HibernateUtils.openSession();
      	
      	Transaction tx = session.beginTransaction();
      	
      	Customer c = new Customer();
      	c.setCust_name("Rabbit");
      	
      	LinkMan lm1 = new LinkMan();
      	lm1.setLkm_name("廖凡");
      	LinkMan lm2 = new LinkMan();
      	lm2.setLkm_name("lwf");
      	//1对多关系,客户下有多个联系人
      	c.getLinkmens().add(lm1);
      	c.getLinkmens().add(lm2);
      	//表达多对1,联系人属于哪个客户
      	lm1.setCustomer(c);
      	lm2.setCustomer(c);
      	
      	session.save(c);
      	tx.commit();
      	session.close();
      }
    

1对多,多对1关系操作:进阶—关系维护属性:保存时,两个表都会维护;冗余了多余的维护关系语句;功能:减少hibernate执行的语句,提高效率

  • 配置Customer的orm文件下的 set标签中的 inverse属性

      		 <!-- inverse属性:配置关系是否维护
      				true:customer:不维护关系
      				false(默认值):customer维护关系
      		
      		 -->
      		<set name="linkmens" cascade="save-update" inverse="true">
      	    		 <!-- 外键列名 -->
      	    			<key column="lkm_cust_id"></key>
      	    			 <!-- 与我关联的完整类名(因为上面已经指定了包位置,所以这里可以写简单类名) -->
      	    			<one-to-many class="LinkMan"/>
      	    		</set>
    
  • 注意1:多的一方不能放弃维护(就是外键字段所在方);只有一的一方可以放弃维护;

  • 注意1 :这种状态下不能删除一的一方,因为它不维护关系,但被多的一方引用,需要先将多的一方的外键引用设置为null;或者将cascade设置为"delete";

多对多

  • 用员工表跟角色表来举例:外键用一个新表来充当:至少两个字段

  • 员工orm配置文件:

      <?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">
          <!-- package 属性 填写一个包名,写了包名之后,需要填写完整类名的可以直接写简单类名 -->
       <hibernate-mapping package="com.rabbit.domain">
          	<class name="User" table="sys_user">
          		<id name="user_id" column="user_id">
          			<generator class="native"></generator>
          		</id>
          		<property name="user_code" ></property>
          		<property name="user_name"></property>
          		<property name="user_password"></property>
          		<property name="user_state"></property>
          	
          			<!-- 
          			 	多对多关系表达
          			 	
          			 	name:集合属性名
          			 	table:配置中间表名
          			 	
          			 	key:column:外键,别人引用我的外键名
          			 			
          			 			class : 我与哪个类是多对多关系
          			 			column:外键,我引用别人的外键列名
          			 -->
          		<set name="roles" table="sys_user_role" cascade="save-update" inverse="true">
          		 <!-- 外键列名 -->
          			<key column="user_id"></key>
          			 <!-- 与我关联的完整类名(因为上面已经指定了包位置,所以这里可以写简单类名) -->
          			<many-to-many class="Role" column="role_id"/>
          		</set>
          		
          		
          	</class>
          </hibernate-mapping>
    
  • 角色orm配置文件:

      <?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">
          <!-- package 属性 填写一个包名,写了包名之后,需要填写完整类名的可以直接写简单类名 -->
       <hibernate-mapping package="com.rabbit.domain">
          	<class name="Role" table="sys_role">
          		<id name="role_id" column="role_id">
          			<generator class="native"></generator>
          		</id>
          		<property name="role_name" ></property>
          		<property name="role_melo"></property>
          		<!-- 集合,一对多关系,在配置文件中配置 -->
          			<!-- 集合属性名 name-->
          			<!-- 级联操作cascade
          						save-update:级联保存更新
          						delete:级联删除
          						all :delete+save-update
          			 -->
          			 <!-- inverse属性:配置关系是否维护
          					true:customer:不维护关系
          					false(默认值):customer维护关系
          			
          			 -->
          		<set name="users" table="sys_user_role" cascade="save-update" inverse="true">
          		 <!-- 外键列名 -->
          			<key column="role_di"></key>
          			 <!-- 与我关联的完整类名(因为上面已经指定了包位置,所以这里可以写简单类名) -->
          			<many-to-many class="User" column="user_id"/>
          		</set>
          		
          		
          	</class>
          </hibernate-mapping>
    

测试:向数据库保存数据:

  • 注意:由于多对多需要用一张中间表作为外键,所以两方必须有一方放弃维护关系,只由一方维护关系。也就是一方设置inverse=“true”,另外一方设置为false;

      Test
      	//保存员工以及角色
      	public void fun1() {
      		Session session = HibernateUtils.openSession();
      		Transaction tx = session.beginTransaction();
      		
      		///操作--------------------------
      		//创建两个User
      		User u1 = new User();
      		u1.setUser_name("杨超越");
      		User u2 = new User();
      		u2.setUser_name("肖仰希");
      		//创建两个Role
      		Role r1 = new Role();
      		r1.setRole_name("保安");
      		Role r2 = new Role();
      		r2.setRole_name("保洁");
      		
      		u1.getRoles().add(r1);
      		u1.getRoles().add(r2);
      		u2.getRoles().add(r1);
      		u2.getRoles().add(r2);
      		
      		r1.getUsers().add(u1);
      		r1.getUsers().add(u2);
      		r2.getUsers().add(u1);
      		r2.getUsers().add(u2);
      		
      		session.save(u1);
      		session.save(u2);
      		session.save(r1);
      		session.save(r2);
      		//--------------------
      		tx.commit();
      		session.close();
      	}
    

查询HQL语法

//HQl语法详解
public class Demo3 {
	@Test
	//基本语法
	public void fun1() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql1 = "from com.rabbit.Custuomer";//完整语法
		String hql = "from Customer";//简单语法
		
		Query query = session.createQuery(hql);
		
		List <Customer> list = query.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	//排序语法
	public void fun2() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql1 = "from com.rabbit.domain.Customer order by cust_id asc";//完整语法
		String hql = "from Customer order by cust_id desc";
		
		Query query = session.createQuery(hql);
		
		List <Customer> list = query.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	//条件查询语法
	public void fun3() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql = "from Customer where cust_id=?";
		
		Query query = session.createQuery(hql);
		query.setParameter(0, 3l);
		
		Customer c = (Customer) query.uniqueResult();
		
		System.out.println(c);
		tx.commit();
		session.close();
	}
	@Test
	//分页查询语法
	public void fun4() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql = "from Customer ";
		
		Query query = session.createQuery(hql);
		query.setFirstResult(0);//第0条开始
		query.setMaxResults(2);//取两条
		List<Customer> list = query.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	//统计查询语法
	public void fun5() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
//		String hql = "select count(*) from Customer ";
//		String hql = "select cust_name from Customer ";
		String hql = "select new Customer(cust_id,cust_name) from Customer ";
		
		Query query = session.createQuery(hql);
//		Number n = (Number) query.uniqueResult();
		List<Customer> list = query.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}
//----------------------------------------------------------------------------------
	@Test
	//多表查询语法
	/*
	 * 内连接(迫切):
	 * 				
	 * 外链接:
	 * 				左外(迫切)
	 * 				右外(迫切)
	 */
	public void fun6() {
		//内连接
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql = "from Customer c inner join c.linkmens";
		String hql1 = "from Customer c inner join fetch c.linkmens";//迫切
		Query query = session.createQuery(hql1);
		List<Customer> list = query.list();
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	public void fun7() {
		//左右外链接
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		String hql = "from Customer c left join c.linkmens";//左外
		String hql1 = "from Customer c right join c.linkmens";//右外
		Query query = session.createQuery(hql);
		List<Object []> list = query.list();
		for (Object[] objects : list) {
			System.out.println(Arrays.toString(objects));
		}
		tx.commit();
		session.close();
	}

查询Criteria语法

基本查询:

//criteria语法
public class Demo4 {

	@Test
	public void fun1() {
		//基本语法
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		
		Criteria c = session.createCriteria(Customer.class);
		List<Customer> list = c.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	public void fun2() {
		//条件语法
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		
		Criteria c = session.createCriteria(Customer.class);
		c.add(Restrictions.idEq(3l));	//id为3的数据
		List<Customer> list = c.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	public void fun3() {
		//分页语法
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		
		Criteria c = session.createCriteria(Customer.class);
		c.setFirstResult(0);
		c.setMaxResults(2);
		List<Customer> list = c.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	public void fun4() {
		//排序语法
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		
		Criteria c = session.createCriteria(Customer.class);
		c.addOrder(Order.desc("cust_id"));
		List<Customer> list = c.list();
		
		System.out.println(list);
		tx.commit();
		session.close();
	}
	@Test
	public void fun5() {
		//统计语法
		Session session = HibernateUtils.openSession();
		
		Transaction tx = session.beginTransaction();
		
		Criteria c = session.createCriteria(Customer.class);
		c.setProjection(Projections.rowCount());//==select count(*) from cst_customer
		Number n = (Number) c.uniqueResult();
		
		System.out.println(n);
		tx.commit();
		session.close();
	}

离线查询Criteria:

  • 基本Criteria是通过session创建

  • 离线查询可以直接凭空创建Criteria对象;组装查询条件;

  • 作用:可以使用一个Dao层方法实现多种查询方式;只需要在web层创建Criteria,组装查询条件传过去就行;

      //--------离线Criteria查询--------------
      @Test
      public void fun6() {
      	DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
      	Session session = HibernateUtils.openSession();
      	Transaction tx = session.beginTransaction();
      	dc.add(Restrictions.idEq(3l));
      	//
      	Criteria c = dc.getExecutableCriteria(session);
      	List list = c.list();
      	System.out.println(list);
      	tx.commit();
      	session.close();
      }
    

查询优化

类级别查询:

  • 懒加载/延迟加载(建议使用):

      //懒加载/延迟加载
      //是否延迟加载:可以通过在配置文件class元素上配置lazy属性来控制:lazy="true"加载时不查询
      public class Demo5 {
      	@Test
      	public void fun1() {
      		Session session = HibernateUtils.openSession();
      		Transaction tx = session.beginTransaction();
      		//load()方法实在执行时不发送任何sql语句,会先返回一个对象,在使用该对象时,才执行查询
      		Customer c = session.load(Customer.class, 3l);
      		System.out.println(c);
      		tx.commit();
      		session.close();
      	}
    

关联级别查询:为了提高效率,fetch的选择应选select。lazy的选择应选择true;全使用默认值

orm配置文件Set标签里的两个属性:集合关联Cusomer.hbm.xml

			 		lazy:决定是否延迟加载
			 				true;延迟加载
			 				false;立即加载
			 				extra:极其懒惰;----与懒加载基本一致,只有在查询size的时候会只查询count;
			 		fetch:决定加载策略,使用什么类型的sql语句加载集合数据
			 				select(默认值); -----------单表查询
			 				join:使用多表查询加载集合------多表查询,当fetch="join",lazy属性全部无效,全部立即加载
			 				subselect:使用子查询加载集合	

对象策略加载;策略关联:LinkMan.hbm.xml

	fetch: 决定加载的sql语句
		select :使用单表查询
		join:多表查询; 当为join时,lazy直接失效
	lazy:决定加载时机
		false:立即加载
		proxy(默认值):由Customer的lazy决定,如果Customer的为true

no-session问题解决:扩大session的作用范围,设置Filter,在放行前打开session,放行后关闭session

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值