框架-Hibernate

Hibernate第一天

1. 搭建Hibernate环境

  • 搭建Hibernate开发环境

    数据库:

    DROP TABLE IF EXISTS `cst_customer`;
    CREATE TABLE `cst_customer` (
      `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
      `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
      `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
      `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
      `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
      `cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
      `cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of cst_customer
    -- ----------------------------
    INSERT INTO `cst_customer` VALUES ('94', '张三', null, null, null, null, null);
    INSERT INTO `cst_customer` VALUES ('95', '李四', '湖北', '湖北大学', null, null, null);
    INSERT INTO `cst_customer` VALUES ('96', '赵四', null, null, null, null, null);
    INSERT INTO `cst_customer` VALUES ('97', '赵四', null, null, null, null, null);
    INSERT INTO `cst_customer` VALUES ('98', '赵四', null, null, null, null, null);
    INSERT INTO `cst_customer` VALUES ('99', '赵四', null, null, null, null, null);
    INSERT INTO `cst_customer` VALUES ('100', 'aaaa', null, null, null, null, null);
    
    
    DROP TABLE IF EXISTS `cst_linkman`;
    CREATE TABLE `cst_linkman` (
      `lkmId` bigint(20) NOT NULL AUTO_INCREMENT,
      `lkm_name` varchar(255) DEFAULT NULL,
      `lkm_gender` varchar(255) DEFAULT NULL,
      `lkm_phone` varchar(255) DEFAULT NULL,
      `lkm_mobile` varchar(255) DEFAULT NULL,
      `lkm_email` varchar(255) DEFAULT NULL,
      `lkm_position` varchar(255) DEFAULT NULL,
      `lkm_memo` varchar(255) DEFAULT NULL,
      `lkm_cust_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`lkmId`),
      KEY `FKh9yp1nql5227xxcopuxqx2e7q` (`lkm_cust_id`)
    ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    

导包:\hibernate-release-5.3.9.Final\lib\required , 再添加连接数据的jar包

创建Customer.java实体对象

创建一个Customer.hbm(Hibernate mapping).xml,然后导约束,约束在 hibernate-core-5.3.9.Final.jar 中。

在这里插入图片描述

在这里插入图片描述

  • Customer.hbm.xml

    <?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 package="com.zwd.domain">
    	<class name="Customer" table="cst_customer">
    		<id name="custId" column="cust_id">
    			<!-- generator:是指定主键的生成方式。取值是固定的几个之中选一个
    			                native是使用本地数据库的自动增长能力。 -->
    			<generator class="native"></generator>
    		</id>
    		<property name="custName" column="cust_name"></property>
    		<property name="custSource" column="cust_source"></property>
    		<property name="custIndustry" column="cust_industry"></property>
    		<property name="custLevel" column="cust_level"></property>
    		<property name="custAddress" column="cust_address"></property>
    		<property name="custPhone" column="cust_phone"></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>
    	<!-- 配置SessionFactory
    		     SessionFactory的作用就是用于创建Session对象。
    		     Session对象就是hibernate中操作数据库的核心对象。
    		 此处的操作不要求背,但是要求记住创建SessionFactory必须的三部分信息
    		      第一部分:连接数据库的信息
    		      第二部分:hibernate的可选配置
    		      第三部分:映射文件的位置 -->
    	<session-factory>
    		<!-- 第一部分:连接数据库的信息:可在hibernate包中查找相应的配置
    		\hibernate-release-5.3.9.Final\project\etc\hibernate.properties -->
    		<!-- 
    		## MySQL
    			#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.dialect">org.hibernate.dialect.MySQLDialect</property><!-- 数据库方言 -->
    		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    		<property name="hibernate.connection.url">jbdc:mysql://localhost:3306/spring</property>
    		<property name="hibernate.connection.username">root</property>
    		<property name="hibernate.connection.password">root</property>
    	
    		<!-- 第二部分:hibernate的可选配置 -->
    		<property name="hibernate.show_sql">true</property>  <!-- 是否显示生成sql语句 -->
    		<property name="hibernate.format_sql">true</property> <!-- 是否使用格式化生成sql语句 -->
    		<!-- 配置hibernate采用何种方式来生产DDL语句 -->
    		<property name="hibernate.hbm2ddl.auto">update</property> <!-- update表示检查实体类的映射配置和数据库的表结构是否一致,如果不一致则更改数据库表结构 -->
    		
    		<!-- SQL结构化查询语言:一共分为6个部分
    			 DDL:Data Definition Language 数据定义语言(建库、建表、创建表结构修改表结构)
    			 DML:Data Manipulation Language 数据操纵语言(增、删、改)
    			 DQL:Data Query Language 数据查询语言 (查)
    			 DCL:Data Control Language 数据控制语言(授权)
    			 CCL:Cursor Control Language 游标控制语言
    			 TPL: Transaction Processing Language 事务处理语言
    			 -->
    			 
    		<!-- 第三部分:配置映射文件的位置 -->
    		<mapping resource="com/zwd/domain/Customer.hbm.xml"/>
    	</session-factory>
    </hibernate-configuration>
    

2 Hibernate入门案例

测试:

  package com.zwd.test;
  
  import org.hibernate.Session;
  import org.hibernate.SessionFactory;
  import org.hibernate.Transaction;
  import org.hibernate.cfg.Configuration;
  import org.junit.Test;
  
  import com.zwd.domain.Customer;
  
  /**
   * hibernate的入门案例(保存客户)
   * 
   * @author Administrator
   *
   */
  public class Test1 {
  	/**
  	 * 步骤: 1.解析hibernate的主配置文件 2.根据配置文件创建SessionFactory
  	 * 3.根据SessionFactory创建Session 4.开始事务 5.执行操作 6.提交事务 7.释放资源
  	 */
  	@Test
  	public void test1() {
  		Customer customer = new Customer();
  		customer.setCustName("hibernate01");
  		// 1.解析hibernate的主配置文件
  		Configuration cfg = new Configuration();
  		cfg.configure();// 在内路径下加载配置文件 cfg.configure("Hibernate.cfg.xml");
  		// 2.根据配置文件创建SessionFactory
  		SessionFactory sessionFactory = cfg.buildSessionFactory();
  		// 3.根据SessionFactory创建Session
  		Session session = sessionFactory.openSession();
  		// 4.开始事务
  		Transaction transaction = session.beginTransaction();
  		// 5.执行操作
  		session.save(customer);
  		// 6.提交事务
  		transaction.commit();
  		// 7.释放资源
  		session.close();
  		sessionFactory.close();
  	}
  }

出现的问题:https://blog.csdn.net/jerny2017/article/details/81982454

在这里插入图片描述

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near**‘type=MyISAM’ at line 10**

解决办法:更改数据库方言,指定mysql的版本 。MySQL5Dialect

<!-- 数据库方言 -->
<!--<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>-->                
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

3.Hibernate的常用对象

Configuration:

SessionFactory: 使用原则:一个应用应该只有一个SessionFactory,在应用加载时创建,应用卸载时销毁。

Session: 它是负责操作数据库,我们要掌握该对象中操作数据库的方法。

​ 使用原则:一个线程只能有一个Session对象。单线程对象。

Transaction: 负责提交和回滚事务。

4.Hibernate CRUD操作

  • 由于SessionFactory只在应用创建一次,所以需要写一个工具类来实现。HibernateUtil.java

    package com.zwd.utils;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    /**
     * Hibernate的工具类
     * 		用于加载配置、创建一个应用的SessionFactory
     * 		
     * @author Administrator
     *
     */
    public class HibernateUtil {
    	private static SessionFactory sessionFactory ;
    	//加载配置,并创建sessionFactory
    	static{
    		Configuration cfg = new Configuration();
    		cfg.configure();
    	    sessionFactory = cfg.buildSessionFactory();
    	}
    	
    	/**
    	 * 获取一个新的Session(一个线程一个Session)
    	 * @return
    	 */
    	public static Session getSession(){
    		return sessionFactory.openSession();
    	}
    }
    
  • hibernate的CRUD操作

       保存: session.save(obj);
    查询一个: session.get(class,primaryKey)、session.load(class,primaryKey)
       更新: session.update(obj)
       删除: session.delete(obj)
    查询所有:
    	方式一: (不常用)
            SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
    		
    		List<Object[]> list = sqlQuery.list();
    		for (Object[] os : list) {
    			System.out.println("===========数组中的内容==========");
    			for (Object o : os) {
    				System.out.println(o);
    			}
    		}
    
  package com.zwd.test;
  
  import java.util.List;
  
  import org.hibernate.SQLQuery;
  import org.hibernate.Session;
  import org.hibernate.Transaction;
  import org.junit.Test;
  
  import com.zwd.domain.Customer;
  import com.zwd.utils.HibernateUtil;
  
  @SuppressWarnings("deprecation")
  public class HibernateDemo1 {
  	/**
  	 * 保存 session.save(obj);
  	 */
  	@Test
  	public void testSave() {
  		Customer c = new Customer();
  		c.setCustName("Hinernate02");
  		
  		Session session = HibernateUtil.getSession();
  		Transaction tx = session.beginTransaction();
  		//保存客户
  		session.save(c);
  		tx.commit();
  		session.close();
  	}
  
  	/**
  	 * 查询一个:session.get(class,primaryKey)
  	 */
  	@Test
  	public void testFindOne() {
  		Session session = HibernateUtil.getSession();
  		Transaction tx = session.beginTransaction();
  		//查询一个
  		Customer customer = session.get(Customer.class,6);
  		System.out.println(customer);
  		tx.commit();
  		session.close();
  	}
  
  	/**
  	 * 更新:session.update(obj)
  	 */
  	@Test
  	public void testUpdate() {
  		Session session = HibernateUtil.getSession();
  		Transaction tx = session.beginTransaction();
  		
  		Customer customer = session.get(Customer.class,6);
  		customer.setCustAddress("贵州遵义");
  		//更新
  		session.update(customer);
  		tx.commit();
  		session.close();
  	}
  
  	/**
  	 * 删除:session.delete(obj)
  	 */
  	@Test
  	public void testDelete() {
  		Session session = HibernateUtil.getSession();
  		Transaction tx = session.beginTransaction();
  		
  		Customer customer = session.get(Customer.class, 6);
  		//删除
  		session.delete(customer);
  		tx.commit();
  		session.close();
  	}
  
  	@Test
  	public void testFindAll() {
  		Session session = HibernateUtil.getSession();
  		Transaction tx = session.beginTransaction();
  		//之后不用这个,用session.createQuery(arg0)
  		SQLQuery sqlQuery = session.createSQLQuery("select * from cst_customer");
  		
  		List<Object[]> list = sqlQuery.list();
  		for (Object[] os : list) {
  			System.out.println("===========数组中的内容==========");
  			for (Object o : os) {
  				System.out.println(o);
  			}
  		}
  	}
  }

5.在hibernate中配置连接池

如果没有使用连接池就是使用的是原始的JDBC

  • 导入c3p0的jar包 \hibernate-release-5.3.9.Final\lib\optional\c3p0

  • 在hibernate的配置文件中添加配置

    可在hibernate包中查找相应的配置

    \hibernate-release-5.3.9.Final\project\etc\hibernate.properties

    <!-- 配置c3p0连接池 -->
    		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    
    /**
    	 * hibernate中 如何使用原始JDBC API
    	 * JDBC中的API:
    	 * 				Connection
    	 * 				Statement
    	 * 				PreparedStatement
    	 * 				ResultSet
    	 */
    	@Test
    	public void testc3p0(){
    		//1.获取session对象
    		Session session = HibernateUtil.getSession();
    		//2.调用doWork方法
    		session.doWork(new Work() {
    			@Override
    			public void execute(Connection arg0) throws SQLException {
    				System.out.println(arg0);
    			}
    		});
    	}
    

6.Hibrnate 查询一个的两种方式的异同(get()、load())

  Hibernate中查询一个的方法
  	get方法:
  		get(Class clazz,Serialized id);
  	load方法:
 		load(Class clazz,Serialized id);
 	共同点:都是根据id查询一个实体
 	区别:
 		1、查询的时机不一样。
 			get的查询时机:每次调用get方法时,马上发起查询。(立即加载)
 			load的查询时机:每次真正使用的时候,发起查询。    (延迟加载、懒加载、惰性加载)
 		2、返回结果不一样。
 			get方法返回的对象是实体对象。
 			load方法返回的对象是实体类类型的代理对象。
 	load方法默认情况下是延迟,但是可以通过配置的方式改为立即加载。(Hibernate第三天再讲)
/**
	 * Hibernate中查询一个的方法
	 * 	get方法:
	 * 		get(Class clazz,Serialized id);
	 * 	load方法:
	 *		load(Class clazz,Serialized id);
	 *	共同点:都是根据id查询一个实体
	 *	区别:
	 *		1、查询的时机不一样。
	 *			get的查询时机:每次调用get方法时,马上发起查询。(立即加载)
	 *			load的查询时机:每次真正使用的时候,发起查询。    (延迟加载、懒加载、惰性加载)
	 *		2、返回结果不一样。
	 *			get方法返回的对象是实体对象。
	 *			load方法返回的对象是实体类类型的代理对象。
	 *	load方法默认情况下是延迟,但是可以通过配置的方式改为立即加载。(Hibernate第三天再讲)
	 */
	@Test
	public void testGet(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		Customer customer = session.get(Customer.class, 5);
		System.out.println("get: " + customer);
		
		tx.commit();
		session.close();
	}
	
	@Test
	public void testLoad(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		Customer customer = session.load(Customer.class, 5);
		System.out.println("load : "+ customer);
		
		tx.commit();
		session.close();
	}

Hibernate第二天

1.实体类的编写规范

​ 应该遵循JavaBean的编写规范。

​ Bean:在软件开发中指的是可重用的组件。

​ JavaBean:指的是用java语言编写的可重用的组件。在实际项目中:domain,service,dao都可以看成是JavaBean。

实体类的编写规范:

​ (1)类都是public的

​ (2)一般实现序列化接口

​ (3)类成员(字段)都是私有的

​ (4)私有的类成员都有公有的get/set方法

​ (5)类都有默认无参构造函数

​ (6)数据类型的选择:基本数据类型和包装类应该选择包装类型。包装类型的默认值为null,基本数据类型的初始值默认值为0 。

2.Hibernate中的OID(object identifier)

在这里插入图片描述

3.Hibernate的主键生产策略

		<id name="custId" column="cust_id">
			<!-- generator:是指定主键的生成方式。取值是固定的几个之中选一个
			                native是使用本地数据库的自动增长能力。 -->
			<generator class="native"></generator>
		</id>

在这里插入图片描述

在这里插入图片描述

4.Hibernate的一级缓存

什么是缓存?
	它就是内存中的临时数据。
为什么使用缓存?
	减少和数据库交互的次数,从而提高查询效率。
什么样的数据适用于缓存,什么样的数据不适用缓存?
	适用缓存的数据:经常查询的,并且不经常修改的。同时数据一旦出现问题,对最终结果影响不大的。
	不适用缓存的数据:不管是否经常查询,只要是经常修改的,都可以不用缓存。
					并且如果数据由于使用缓存,产生了异常数据,对最终结果影响很大,则不能使用。

Hibernate的一级缓存:

/**
	 * 测试Hibernate的一级缓存
	 */
	@Test
	public void testCache(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		//1.根据id查询客户
		//先去数据库查询记录,并将记录放入一级缓存中
		Customer customer1 = session.get(Customer.class, 5);
		System.out.println(customer1);
		//2.再次根据id查询用户
		//先去一级缓存中查询是否有这条记录,如果有,直接拿过来,如果没有再去数据库中查询
		Customer customer2 = session.get(Customer.class, 5);//这里hibernate并没有打印sql语句,因为并没有去数据库中查询
		System.out.println(customer2);
		
		System.out.println(customer1 == customer2);
		
	    tx.commit();
		session.close();//session关闭,一级缓存就消失了
	}

结果:只有第一次查询的时候向数据库中查询了。

Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_address as cust_add6_0_0_, customer0_.cust_phone as cust_pho7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
{'custId':'5','custName':'9','custSource':'null','custIndustry':'null','custLevel':'null','custAddress':'null','custPhone':'null'}
{'custId':'5','custName':'9','custSource':'null','custIndustry':'null','custLevel':'null','custAddress':'null','custPhone':'null'}
true
    
    

Session缓存机制:Session内部是一个 map<Class,Map<Object,Object>> ,通过类的字节码获取到该对的缓存map,然后通过OID获取。

在这里插入图片描述

5.Hibernate 的快照机制

先看一段代码:

	/**
	 * Hibernate的快照机制
	 */
	@Test
	public void testQuickPhoto(){
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		//1.根据ID查询客户
		//Hibernate在查询到客户后,将该对象保存在一级缓存中,并且同时保存在快照区中
		Customer customer1 = session.get(Customer.class, 5);
		System.out.println(customer1.getCustAddress());//输出客户的地址:武汉
		
		//2.修改客户的地址 遵义-----此处修改的是一级缓存中的对象
		customer1.setCustAddress("遵义");
		System.out.println(customer1.getCustAddress());//输出客户的地址:遵义
		
		//没有写update语句
		//在提交时,Hibernate会比较一级缓存中的该对象和快照中的是否一致,如果不一致,更新数据库,所以在此处会有一句update打印语句
		tx.commit();
		session.close();//session关闭
		
		System.out.println(customer1.getCustAddress());//此处输出的是数据库中的值 :遵义
	}

Session中有一个一级缓存容器,还有一个快照区 。当执行该语句时session.get(Customer.class, 5);,Hibernate会把这个对象分别放在一级缓存以及快照(应该是那个对象的副本)中,修改该对象会改变一级缓存中的值,当执行 tx.commit(); 时,发现一级缓存中的对象属性值和快照不一致(通过OID比对),Hibernate

会更新数据库中的该条记录。

在这里插入图片描述

6.Hibernate中对象的四种状态

(1) 临时状态(瞬时状态):没有OID,和Session无关。刚用 new 关键字创建的对象
(2) 持久状态:有OID,和Session有关。将临时状态进行保存操作、从数据库中查询的记录,对象为持久状态。
(3) 托管状态:有OID,和Session无关。关闭(或者清除clear)session后,持久状态的对象会变为托管状态。
			托管状态的对象变为持久状态:更新操作。
(4) 删除状态:有OID,和Session有关。同时已经调用了删除方法 session.delete(obj),但是事务还没提交。 				此时对象的状态为删除状态。

在这里插入图片描述

	/**
	 * 对象的状态
	 */
	@Test
	public void testStateOfObj(){
		Customer c = new Customer();//c:临时状态
		c.setCustAddress("贵州");
		
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		session.save(c);//持久状态;或者 :session.saveOrUpdate(c);
		
		tx.commit();
		session.close();//session关闭,此时c变为托管状态
		//session.clear();//只清除Hibernate中的一级缓存和快照,不关闭session
		c.setCustAddress("上海");
		
		Session session1 = HibernateUtil.getSession();
		Transaction tx1 = session1.beginTransaction();
		session.update(c);//c变为持久状态;  或者:session.saveOrUpdate(c);
		
		tx1.commit();
		session1.close();//session关闭,此时c变为托管状态
	}

7.Hibernate中的事务控制(配置session与线程绑定)

解决的问题:让session对象也符合使用原则。

session对象的使用原则:一个线程只能有一个Session

  • 方法一:使用ThreadLocal保证一个线程只有一个session,但是Hibernate提供配置方法,不用这么做。

    HibernateUtil.java 中添加的代码:

  private static ThreadLocal<Session> tl = new ThreadLocal();
  
  
  	/**
  	 * 利用ThreadLocal保证一个线程一个session
  	 * @return
  	 */
  	public static Session getSession1(){
  		Session s = tl.get();
  		if(s == null){
  		   tl.set(sessionFactory.openSession());
  		}
  		return tl.get();
  	}	
  package com.zwd.utils;
  
  import org.hibernate.Session;
  import org.hibernate.SessionFactory;
  import org.hibernate.cfg.Configuration;
  
  /**
   * Hibernate的工具类
   * 		用于加载配置、创建一个应用的SessionFactory
   * 		
   * @author Administrator
   *
   */
  public class HibernateUtil {
  	private static SessionFactory sessionFactory ;
  	private static ThreadLocal<Session> tl = new ThreadLocal();
  	//加载配置,并创建sessionFactory
  	static{
  		Configuration cfg = new Configuration();
  		cfg.configure();
  	    sessionFactory = cfg.buildSessionFactory();
  	}
  	
  	/**
  	 * 获取一个新的Session(一个线程一个Session)
  	 * @return
  	 */
  	public static Session getSession(){
  		return sessionFactory.openSession();
  	}
  	
  	/**
  	 * 利用ThreadLocal保证一个线程一个session
  	 * @return
  	 */
  	public static Session getSession1(){
  		Session s = tl.get();
  		if(s == null){
  		   tl.set(sessionFactory.openSession());
  		}
  		return tl.get();
  	}	
  }
  
  • 方法二:在Hibernate的配置文件中配置将session和线程绑定,从而实现一个线程只有一个session。

    <!-- 把线程和session绑定,从而实现一个线程只有一个session -->
    <property name="hibernate.current_session_context_class">thread</property>
    
    <?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对象。
    		     Session对象就是hibernate中操作数据库的核心对象。
    		 此处的操作不要求背,但是要求记住创建SessionFactory必须的三部分信息
    		      第一部分:连接数据库的信息
    		      第二部分:hibernate的可选配置
    		      第三部分:映射文件的位置 -->
    	<session-factory>
    		<!-- 第一部分:连接数据库的信息:可在hibernate包中查找相应的配置
    		\hibernate-release-5.3.9.Final\project\etc\hibernate.properties -->
    		<!-- 
    		## MySQL
    			#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.dialect">org.hibernate.dialect.MySQL5Dialect</property><!-- 数据库方言 -->
    		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/spring</property>
    		<property name="hibernate.connection.username">root</property>
    		<property name="hibernate.connection.password">root</property>
    	
    		<!-- 第二部分:hibernate的可选配置 -->
    		<property name="hibernate.show_sql">true</property>  <!-- 是否显示生产sql语句 -->
    		<property name="hibernate.format_sql">false</property> <!-- 是否使用格式化生产sql语句 -->
    		<!-- 配置hibernate采用何种方式来产生DDL语句 -->
    		<property name="hibernate.hbm2ddl.auto">update</property> <!-- update表示检查实体类的映射配置和数据库的表结构是否一致,如果不一致则更改数据库表结构 -->
    		<!-- 把线程和session绑定,从而实现一个线程只有一个session -->
    		<property name="hibernate.current_session_context_class">thread</property>
    		<!-- 配置c3p0连接池 -->
    		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    		<!-- SQL结构化查询语言:一共分为6个部分
    			 DDL:Data Definition Language 数据定义语言(建库、建表、创建表结构修改表结构)
    			 DML:Data Manipulation Language 数据操纵语言(增、删、改)
    			 DQL:Data Query Language 数据查询语言 (查)
    			 DCL:Data Control Language 数据控制语言(授权)
    			 CCL:Cursor Control Language 游标控制语言
    			 TPL: Transaction Processing Language 事务处理语言
    			 -->
    			 
    		<!-- 第三部分:配置映射文件的位置 -->
    		<mapping resource="com/zwd/domain/Customer.hbm.xml"/>
    	</session-factory>
    </hibernate-configuration>
    

    在获取Session对象的时候也有相应的方法 sessionFactory.getCurrentSession() ,必须在hibernate的配置文件中配置之后才可用这个方法,不然返回值为null。

    HibernateUtil.java

  /**
  	 * 3.在hibernate中配置:使session和线程绑定在一起,从而实现一个线程一个session
  	 *	在线程上获取Session对象。
  	 * @return
  	 */
  	public static Session getCurrentSession(){
  		return sessionFactory.getCurrentSession();//必须在hibernate的配置文件中配置之后才可用这个方法,不然返回值为null.
  	}
  package com.zwd.utils;
  
  import org.hibernate.Session;
  import org.hibernate.SessionFactory;
  import org.hibernate.cfg.Configuration;
  
  /**
   * Hibernate的工具类
   * 		用于加载配置、创建一个应用的SessionFactory
   * 		
   * @author Administrator
   *
   */
  public class HibernateUtil {
  	private static SessionFactory sessionFactory ;
  	//private static ThreadLocal<Session> tl = new ThreadLocal();
  	//加载配置,并创建sessionFactory
  	static{
  		Configuration cfg = new Configuration();
  		cfg.configure();
  	    sessionFactory = cfg.buildSessionFactory();
  	}
  	
  	/**
  	 * 1.获取一个新的Session(每次获取都会获取到一个新的session)
  	 * @return
  	 */
  	public static Session getSession(){
  		return sessionFactory.openSession();
  	}
  	
  	/**
  	 * 2.利用ThreadLocal保证一个线程一个session
  	 * @return
  	 */
  //	public static Session getSession1(){
  //		Session s = tl.get();
  //		if(s == null){
  //		   tl.set(sessionFactory.openSession());
  //		}
  //		return tl.get();
  //	}
  	/**
  	 * 3.在hibernate中配置:使session和线程绑定在一起,从而实现一个线程一个session
  	 *	在线程上获取Session对象。
  	 * @return
  	 */
  	public static Session getCurrentSession(){
  		return sessionFactory.getCurrentSession();//必须在hibernate的配置文件中配置之后才可用这个方法,不然返回值为null.
  	}
  }

在使用session的时候,不需要我们手动关闭session,
​ 当我们把session和线程绑定之后,hibernate就会在提交或者回滚事务之后,自动帮我们关闭session。

  	/**
  	 * 使用Hiberbate对session的配置后,
  	 * 测试一个线程只有一个session,
  	 * 并且不需要我们手动关闭session,
  	 * 当我们把session和线程绑定之后,hibernate就会在提交或者回滚事务之后,自动帮我们关闭session
  	 */
  	@Test
  	public void testSession(){
  //		Session s1 = HibernateUtil.getCurrentSession();
  //		Session s2 = HibernateUtil.getCurrentSession();
  //		System.out.println(s1 == s2);
  //		
  		Customer c = new Customer();//c:临时状态
  		c.setCustAddress("深圳1");
  		
  		Session session = HibernateUtil.getCurrentSession();
  		System.out.println(session);
  		Transaction tx = session.beginTransaction();
  		session.saveOrUpdate(c);//持久状态;或者 :session.saveOrUpdate(c);
  		
  		tx.commit();
  		//session.close();// 不需要手动关闭session,事务提交之后session确实不可用了,但是我手动关闭并没有报错
  		session.get(Customer.class, 5);
  		System.out.println(session.isOpen());
  	}

8.Hibernate中的5中查询

  • OID查询:

    ​ 根据id查询一个实体。

    ​ 涉及的方法: get()load()

  • SQL查询:

    ​ 使用SQL语句查询数据库。

    ​ 涉及的方式有两种:

    ​ 第一种:SQLQuery() ------一般不怎么用

    ​ 第二种:session的doWork()方法,它可以拿到Connection

  • HQL查询:

    ​ 使用HQL语句查询数据库。

  • QBC查询:

    ​ 使用Criteria对象查询数据库。

  • 对象导航查询:

8.1 Hibernate中的HQL查询–Hibernate Query Language

	它是hibernate中的HQL查询方式
	HQL:hibernate query language
	如何获取该对象:session对象的方法
	涉及的对象和方法: createQuery(String hql)
    方法中参数的含义:
    	SQL:select cust_id from cst_customer
    	HQL:select custId from Customer
    	HQL语句:是把sql语句的表名换成类名,把字段名换成实体类中的属性名称。
        
  • 基本查询:

    //基本查询
    	@Test
    	public void test1(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		//1.获取Query对象
    		Query query = session.createQuery("from Customer");
    		//2.获取结果集
    		List list = query.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 条件查询:

    //条件查询
    	@Test
    	public void test2(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		
    		//1.只有问号的占位符已经不能用了,会报错
    		//Query query = session.createQuery("from Customer where custLevel = ?");
    		//query.setParameter(1, "23");
    		
    		//2.占位符方式一: ?数字
    		Query query = session.createQuery("from Customer where custLevel = ?0");
    		query.setParameter(0, "23");
    		
    		//3.占位符方式二: :名称
    		Query query = session.createQuery("from Customer where custLevel = :custLevel and custAddress like :custAddress");
    		query.setParameter("custLevel", "23");
    		query.setParameter("custAddress", "%深圳%");
    		
    		List list = query.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    

    1.只有问号的占位符已经不能用了,会报错

Caused by: org.hibernate.QueryException: Legacy-style query parameters (`?`) are no longer supported; use JPA-style ordinal parameters (e.g., `?1`) instead : from com.zwd.domain.Customer where custLevel = ?

  • 排序查询:
/**排序查询:
	 * 		降序:order by desc; 
	 * 		升序:order by asc
	 */
	@Test
	public void test3(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Query query = session.createQuery("from Customer order by custId desc");
		List list = query.list();
		for (Object object : list) {
			System.out.println(object);
		}
		tx.commit();
	}
  • 分页查询:

    /**分页查询
    	 * 
    	 * MySql分页关键字:
    	 * 		limit
    	 * limit的两个参数含义:
    	 * 		第一个:查询的开始记录索引(等于 (当前页-1)*每页条数)
    	 * 		第二个:每次查询的条数
    	 * Hibernate为我们提供了两个方法:Mysql和Oracle都可用这个(设置不同的方言即可)
    	 * 		setFirstResult:设置查询的开始记录索引
    	 * 		setMaxResults:设置每次查询的条数
    	 */
    	@Test
    	public void test4(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		//1.获取Query对象
    		Query query = session.createQuery("from Customer");
    		query.setFirstResult(0);//从0开始
    		query.setMaxResults(2);
    		//2.获取结果集
    		List list = query.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 统计查询: query.uniqueResult();//返回一个唯一的结果,如果结果不唯一则会抛异

/**统计查询
	 * 	    聚合函数:count、sum、max、min、avg
	 * 
	 */
	@Test
	public void test5(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//1.获取Query对象
		Query query = session.createQuery("select count(*) from Customer");
		//2.获取结果集
		long count = (long) query.uniqueResult();//返回一个唯一的结果,如果结果不唯一则会抛异常。
		tx.commit();
	}
  • 投影查询: 当我们在查询实体时,只需要部分字段,而不是全部。并且希望它的返回结果使用实体类来封装,而不是Object[],这个时候我们称之为创建实体类的投影。

    当只查询部分字段时返回的是数组。

    	@Test
    	public void test6(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		//1.获取Query对象
    		Query query = session.createQuery("select custId,custName from Customer");//返回结果的每条记录将会在一个数组中
    		//2.获取结果集
    		List<Object[]> list = query.list();
    		for (Object[] os : list) {
    			System.out.println("======每个数组中的内容=======");
    			for (Object o : os) {
    				System.out.println(o);
    			}
    		}
    		tx.commit();
    	}
    

    使用投影:将返回的结果封装成实体类。

    投影查询的用法:

    • 1、查询语句时需要使用new关键字。

      session.createQuery("select new com.zwd.domain.Customer(custId,custName) from Customer");
      
    • 2、在实体类中添加对应参数的构造函数。添加之后注意实体类的编写规范

      //当添加了带参数的构造函数后,需要自己再添加一个无参构造函数
      	public Customer() {
      		
      	}
      	
      	public Customer(int custId, String custName) {
      		this.custId = custId;
      		this.custName = custName;
      	}
      
  	/**投影查询
  	 *   当我们在查询实体时,只需要部分字段,而不是全部。并且希望它的返回结果使用实体类来封装,而不是Object[]
  	 *这个时候我们称之为创建实体类的投影。
  	 *
  	 *	投影查询的用法:
  	 *		1、查询语句时需要使用new关键字。
  	 *		2、在实体类中添加对应参数的构造函数。
  	 *
  	 */
      @Test
  	public void test7(){
  		Session session = HibernateUtil.getCurrentSession();
  		Transaction tx = session.beginTransaction();
  		//1.获取Query对象
  		Query query = session.createQuery("select new com.zwd.domain.Customer(custId,custName) from Customer");
  		//2.获取结果集
  		List list = query.list();
  		for (Object object : list) {
  			System.out.println(object);
  		}
  		tx.commit();
  	}

8.2 Hibernate中的QBC查询–Query By Criteria

Hibernate中的Criteria对象:
	它是hibernate中QBC查询的方式。
	QBC: Query By Criteria
	如何获取该对象:
			session.createCriteria(Class clazz);
    涉及对象的方法:
    		createCriteria(Class clazz);
	参数的含义:要查询的实体类字节码。
  • 基本查询:

    // 基本查询
    	@Test
    	public void test1() {
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		// 获取Criteria对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		// 获取结果集
    		List list = criteria.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 条件查询: 添加条件:criteria.add(Restrictions.eq("custLevel", "23"));

    // 条件查询
    	@Test
    	public void test2() {
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		// 获取Criteria对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		criteria.add(Restrictions.eq("custLevel", "23"));
    		criteria.add(Restrictions.like("custAddress", "%深圳%"));
    		// 获取结果集
    		List list = criteria.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 排序查询: 设置排序:criteria.addOrder(Order.desc("custId"));

    	// 排序查询
    	@Test
    	public void test3() {
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		// 获取Criteria对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		criteria.addOrder(Order.desc("custId"));
    		// 获取结果集
    		List list = criteria.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 分页查询: 和Query对象的一样的方法。criteria.setFirstResult(0);criteria.setMaxResults(2);

    // 分页查询
    	@Test
    	public void test4() {
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		// 获取Criteria对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		criteria.setFirstResult(0);
    		criteria.setMaxResults(2);
    		// 获取结果集
    		List list = criteria.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    	}
    
  • 统计查询: 使用聚合函数:criteria.setProjection(Projections.count("custName"));

    ​ 获取单一结果:criteria.uniqueResult();

    	//统计查询
    	@Test
    	public void test5() {
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		// 获取Criteria对象
    		Criteria criteria = session.createCriteria(Customer.class);
    		//criteria.setProjection(Projections.rowCount());//count(*)
    		criteria.setProjection(Projections.count("custName"));
    		// 获取结果集
    		long count = (long) criteria.uniqueResult();
    		System.out.println(count);
    		tx.commit();
    	}
    
  • 离线查询:
    ​ DetachedCriteria对象,该对象的获取不需要session,可以直接得到,我们使用此对象实现的查询,称之为离线查询。

    ​ Criteria对象的获取需要session。在线对象。

    		//1.获取离线对象
    		DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
    		dc.add(Restrictions.eq("custLevel", "23"));
    		dc.add(Restrictions.like("custAddress", "%深圳%"));
    
            Session session = HibernateUtil.getCurrentSession();
            Transaction tx = session.beginTransaction();
    		//2.把离线对象转为在线对象
    		Criteria criteria = dc.getExecutableCriteria(session);
            //3.获取结果集
    		List list = criteria.list();
        
            tx.commit();
    		
    
    /** 离线查询
    	 *      DetachedCriteria对象,该对象的获取不需要session,可以直接得到,我们使用此对象实现的查询,称之为离线查询。
    	 *      Criteria对象的获取需要session。在线对象。
    	 */
    	@Test
    	public void testServlet(){
    		//获取离线对象
    		DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
    		dc.add(Restrictions.eq("custLevel", "23"));
    		dc.add(Restrictions.like("custAddress", "%深圳%"));
    		
    		List list = testService(dc);
    		for(Object o : list){
    			System.out.println(o);
    		}
    	}
    
    	private List testService(DetachedCriteria dc) {
    		Session session = null;
    		Transaction tx = null;
    		try{
    			session = HibernateUtil.getCurrentSession();
    			tx = session.beginTransaction();
    			List list = testDao(dc);
    			tx.commit();
    			return list;
    		}catch(Exception e){
    			System.out.println(e.getMessage());
    			tx.rollback();
    		}finally{
    			//hibernate已经帮我们关闭了session
    		}
    		return null;
    	}
    
    	private List testDao(DetachedCriteria dc) {
    		Session session = HibernateUtil.getCurrentSession();
    		//把离线对象转为在线对象
    		Criteria criteria = dc.getExecutableCriteria(session);
    		return criteria.list();
    	}
    

8.3 第二天总结

  • 数据表:cst_customer

    DROP TABLE IF EXISTS `cst_customer`;
    CREATE TABLE `cst_customer` (
      `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
      `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
      `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
      `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
      `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
      `cust_address` varchar(128) DEFAULT NULL COMMENT '客户联系地址',
      `cust_phone` varchar(64) DEFAULT NULL COMMENT '客户联系电话',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
    
    
  • 首先创建工程,导Hibernate必须的包 + 数据库连接驱动 + 连接池

  • 创建包 com.zwd.domain ,创建数据库表对应的实体类Customer。注意实体类的编写规范。

  • 在实体类的包下创建实体类的映射文件:在映射id时,记得指定主键生成的方式 。 导入xml文件的dtd约束,约束在hibernate核心包中查找。具体如 Hibernate第一天(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">
        
    <hibernate-mapping package="com.zwd.domain">
    	<class name="Customer" table="cst_customer">
    		<id name="custId" column="cust_id">
    			<generator class="native"></generator> <!-- 指定主键生成方式 -->
    		</id>
    		<property name="custName" column="cust_name"></property>
    		<property name="custSource" column="cust_source"></property>
    		<property name="custIndustry" column="cust_industry"></property>
    		<property name="custLevel" column="cust_level"></property>
    		<property name="custAddress" column="cust_address"></property>
    		<property name="custPhone" column="cust_phone"></property>
    	</class>
    </hibernate-mapping>
    
  • 创建Hibernate的总配置文件: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>
    		<!-- 1.配置连接的数据库信息 -->
    		
    		<!-- 数据库方言 -->
    		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    		<!-- 连接数据的信息 -->
    		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/spring</property>
    		<property name="hibernate.connection.username">root</property>
    		<property name="hibernate.connection.password">root</property>
    		
    		<!-- 2.Hibernate的可选配置 -->
    		
    		<!-- 配置数据库连接池 c3p0 :记得导c3p0的包(在hibernate包的option中)-->
    		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    		<!-- 配置session与线程绑定 -->
    		<property name="hibernate.current_session_context_class">thread</property>
    		<!-- 是否生成sql语句打印 -->
    		<property name="hibernate.show_sql">true</property>
    		<!-- 是否格式化生成sql语句 -->
    		<property name="hibernate.format_sql">true</property>
    		<!-- 采用怎样的方式处理ddl -->
    		<property name="hibernate.hbm2ddl.auto">update</property>
    		
    		<!-- 3.配置映射文件的位置 -->
    		<mapping resource="com/zwd/domain/Customer.xml" />
    	</session-factory>
    </hibernate-configuration>
    
  • hibernate的基本操作过程

    package com.zwd.test;
    
    import java.util.List;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.Transaction;
    import org.hibernate.cfg.Configuration;
    import org.hibernate.query.Query;
    import org.junit.Test;
    
    /**
     * hibernate的基本操作过程
     * 		问题:应用只加载一次配置文件,一个SessionFactory对象即可
     * @author Administrator
     *
     */
    public class HibernateDemoBase {
    	@Test
    	public void test(){
    		//1.读取hibernate的总配置文件
    		Configuration cfg = new Configuration();
    		cfg.configure();//去找类路径下的:Hibernate.cfg.xml,如果没有则会报错
    		//cfg.configure("Hibernate1.cfg.xml");//在类路径中去加载指定文件
    		//2.根据配置获取sessionFactory
    		SessionFactory sessionFactory = cfg.buildSessionFactory();
    		//3.根据sessionFactory获取session
    		//sessionFactory.openSession();
    		Session session = sessionFactory.getCurrentSession();//需配置xml才能使用,保证session的使用原则,一个线程一个session
    		//4.根据session获取并开启事务
    		Transaction tx = session.beginTransaction();
    		//5.操作数据库:两种方式:HQL,使用	Query对象操作。QBC:使用Criteria操作
    		Query query = session.createQuery("from Customer");
    		List list = query.list();
    		for (Object object : list) {
    			System.out.println(object);
    		}
    		tx.commit();
    		//tx.rollback();
    	}
    }
    
  • 将加载配置文件的代码抽取到 HibernateUtil.java中。

    package com.zwd.utils;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    /**
     * Hibernate的工具类:
     * 		用于加载配置文件,以及获取session对象
     * @author Administrator
     *
     */
    public class HibernateUtil {
    	private static SessionFactory sessionFactory = null;
    	//加载配置文件
    	static{
    		Configuration cfg = new Configuration();
    		cfg.configure();//加载配置文件
    		sessionFactory = cfg.buildSessionFactory();
    	}
    	
    	public static Session getSeesion(){
    		return sessionFactory.openSession();
    	}
    	//获取一个线程的session对象,需配置xml文件,该session不需要手动close
    	public static Session getCurrentSession(){
    		return sessionFactory.getCurrentSession();
    	}
    }
    
  • hibernate 中的增、删、改、查一个

       保存: session.save(obj);
    查询一个: session.get(class,primaryKey)、session.load(class,primaryKey)
       更新: session.update(obj)
       删除: session.delete(obj)
    
  • hibernate 的HQL查询(一条或多条):使用得较多,相对QBC要简单一点。

    Query query =  session.createQuery(String hql)
    List list = query.list();//返回多条
    query.uniqueResult();//返回单个值
    
  • hibernate 的QBC查询(一条或多条):

    Criteria criteria = session.createCriteria(Class clazz);
    //设置条件 
    criteria.add(Restrictions.eq("custLevel", "23"));
    //设置排序
    criteria.order(Order.asc("custId"))
    //设置分页
    criteria.setFirstResult(0);
    criteria.setMaxResults(2);
    //设置统计
    criteria.setProjection(Projections.count("custName"));
    //设置离线查询
    	    //1.获取离线对象
    		DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
    		dc.add(Restrictions.eq("custLevel", "23"));
    		dc.add(Restrictions.like("custAddress", "%深圳%"));
    
            Session session = HibernateUtil.getCurrentSession();
            Transaction tx = session.beginTransaction();
    		//2.把离线对象转为在线对象
    		Criteria criteria = dc.getExecutableCriteria(session);
    

Hibernate第三天

1.表之间的关系

  • 数据库中表关系: 一对一、一对多(多对一)、多对多。

  • 如何确立和实现数据库中的表关系

    一对多的表关系在数据库中如何实现?

    ​ 使用外键约束。

    ​ 我们习惯把一的方称为主表,把多的方称为从表。

    ​ 什么是外键:

    ​ 从表中有一列,该列的取值除了null之外,只能来源于主表的主键。

    ​ 默认情况下,外键字段的值是可以重复的。

    多对多的表关系在数据库中如何实现?

    ​ 使用中间表。

    ​ 中间表中只有两个外键,引用两个多对多的主键。

    ​ 不能有其他字段信息,至于中间表的主键,应该采用联合主键。

    ​ 任何一个对方的表和中间表去比较,都是一对多的关系。

    一对一的表关系在数据库如何实现?(两种)

    ​ 第一种:建立外键的方式。

    ​ 使用外键约束,唯一约束,非空约束。

    ​ 它是把外键字段加了非空和唯一约束。从而实现了一对一。

    ​ 第二种:使用主键的方式。

    ​ 让其中一张表既是主键,又是外键。

    如何确立两张表之间的关系:

    ​ 找外键。

2.学习多表映射配置要遵循的步骤

​ 第一步:确立两张表之间的关系。

​ 第二步:在数据库中实现两张表之间的关系

​ 第三步:在实体类中描述出两个实体之间的关系

​ 第四步:在映射配置文件中建立两个实体和两张表之间的关系

3.一对多的关系映射及操作

示例:客户和联系人表之间的关系。

第一步:确立两张表之间的关系。

​ 一个客户可以包含多个联系人。

​ 多个联系人可以属于同一个客户。

​ 所以说:客户和联系人之间的关系是一对多。

第二步:在数据库中实现两张表之间的关系建立。

​ 实现一对多的关系,靠外键。

​ 客户表是主表,联系人表是从表。

​ 我们需要在联系人表中添加外键。

第三步:在实体类中描述出两个实体之间的关系

​ 主表的实体类应该包含从表实体类的集合引用。

​ 从表的实体类应该包含主表实体类的对象引用。

第四步:在映射配置文件中建立两个实体和两张表之间的关系

  • 在实体类中描述出两个实体之间的关系。

    主表的实体类应该包含从表实体类的集合引用。

    	//一对多关系映射:一的一方
    	//主表的实体类应该包含从表实体类的集合引用。
    	Set<LinkMan> set = new HashSet<LinkMan>(0);
    
    package com.zwd.domain;
    
    import java.util.HashSet;
    import java.util.Set;
    
    /*******************************************************************************
     * javaBeans
     * cst_customer --> Customer 
     * <table explanation>
     * @author 2019-08-12 14:43:39
     * 
     */	
    public class Customer implements java.io.Serializable {
    	//field
    	/**  **/
    	private int custId;
    	/**  **/
    	private String custName;
    	/**  **/
    	private String custSource;
    	/**  **/
    	private String custIndustry;
    	/**  **/
    	private String custLevel;
    	/**  **/
    	private String custAddress;
    	/**  **/
    	private String custPhone;
    	/**  **/
    	private String custTest;
    	
    	
    	//一对多关系映射:一的一方
    	//主表的实体类应该包含从表实体类的集合引用。
    	Set<LinkMan> set = new HashSet<LinkMan>(0);
    	
    	
    	public Set<LinkMan> getSet() {
    		return set;
    	}
    	public void setSet(Set<LinkMan> set) {
    		this.set = set;
    	}
    	//method
    	public int getCustId() {
    		return custId;
    	}
    	public void setCustId(int custId) {
    		this.custId = custId;
    	}
    	public String getCustName() {
    		return custName;
    	}
    	public void setCustName(String custName) {
    		this.custName = custName;
    	}
    	public String getCustSource() {
    		return custSource;
    	}
    	public void setCustSource(String custSource) {
    		this.custSource = custSource;
    	}
    	public String getCustIndustry() {
    		return custIndustry;
    	}
    	public void setCustIndustry(String custIndustry) {
    		this.custIndustry = custIndustry;
    	}
    	public String getCustLevel() {
    		return custLevel;
    	}
    	public void setCustLevel(String custLevel) {
    		this.custLevel = custLevel;
    	}
    	public String getCustAddress() {
    		return custAddress;
    	}
    	public void setCustAddress(String custAddress) {
    		this.custAddress = custAddress;
    	}
    	public String getCustPhone() {
    		return custPhone;
    	}
    	public void setCustPhone(String custPhone) {
    		this.custPhone = custPhone;
    	}
    	public String getCustTest() {
    		return custTest;
    	}
    	public void setCustTest(String custTest) {
    		this.custTest = custTest;
    	}
    	//override toString Method 
    	public String toString() {
    		StringBuffer sb=new StringBuffer();
    		sb.append("{");
    		sb.append("'custId':'"+this.getCustId()+"',");
    		sb.append("'custName':'"+this.getCustName()+"',");
    		sb.append("'custSource':'"+this.getCustSource()+"',");
    		sb.append("'custIndustry':'"+this.getCustIndustry()+"',");
    		sb.append("'custLevel':'"+this.getCustLevel()+"',");
    		sb.append("'custAddress':'"+this.getCustAddress()+"',");
    		sb.append("'custPhone':'"+this.getCustPhone()+"',");
    		sb.append("'custTest':'"+this.getCustTest()+"'");
    		sb.append("}");
    		return sb.toString();
    	}
    }
    

    从表的实体类应该包含主表实体类的对象引用。

    	//一对多关系映射:多的一方
    	//从表的实体类应该包含主表实体类的对象引用。
    	private Customer customer;
    
    package com.zwd.domain;
    
    /*******************************************************************************
     * javaBeans
     * cst_linkman --> CstLinkman 
     * <table explanation>
     * @author 2019-08-12 21:30:10
     * 
     */	
    public class LinkMan implements java.io.Serializable {
    	//field
    	/** 联系人编号(主键) **/
    	private long lkmId;
    	/** 联系人姓名 **/
    	private String lkmName;
    	/** 联系人性别 **/
    	private String lkmGender;
    	/** 联系人办公电话 **/
    	private String lkmPhone;
    	/** 联系人手机 **/
    	private String lkmMobile;
    	/** 联系人邮箱 **/
    	private String lkmEmail;
    	/** 联系人职位 **/
    	private String lkmPosition;
    	/** 联系人备注 **/
    	private String lkmMemo;
    	
    	//一对多关系映射:多的一方
    	//从表的实体类应该包含主表实体类的对象引用。
    	private Customer customer;
    	
    	public Customer getCustomer() {
    		return customer;
    	}
    	public void setCustomer(Customer customer) {
    		this.customer = customer;
    	}
    	//method
    	public long getLkmId() {
    		return lkmId;
    	}
    	public void setLkmId(long lkmId) {
    		this.lkmId = lkmId;
    	}
    	public String getLkmName() {
    		return lkmName;
    	}
    	public void setLkmName(String lkmName) {
    		this.lkmName = lkmName;
    	}
    	public String getLkmGender() {
    		return lkmGender;
    	}
    	public void setLkmGender(String lkmGender) {
    		this.lkmGender = lkmGender;
    	}
    	public String getLkmPhone() {
    		return lkmPhone;
    	}
    	public void setLkmPhone(String lkmPhone) {
    		this.lkmPhone = lkmPhone;
    	}
    	public String getLkmMobile() {
    		return lkmMobile;
    	}
    	public void setLkmMobile(String lkmMobile) {
    		this.lkmMobile = lkmMobile;
    	}
    	public String getLkmEmail() {
    		return lkmEmail;
    	}
    	public void setLkmEmail(String lkmEmail) {
    		this.lkmEmail = lkmEmail;
    	}
    	public String getLkmPosition() {
    		return lkmPosition;
    	}
    	public void setLkmPosition(String lkmPosition) {
    		this.lkmPosition = lkmPosition;
    	}
    	public String getLkmMemo() {
    		return lkmMemo;
    	}
    	public void setLkmMemo(String lkmMemo) {
    		this.lkmMemo = lkmMemo;
    	}
    	//override toString Method 
    	public String toString() {
    		StringBuffer sb=new StringBuffer();
    		sb.append("{");
    		sb.append("'1kmId':'"+this.getLkmId()+"',");
    		sb.append("'lkmName':'"+this.getLkmName()+"',");
    		sb.append("'lkmGender':'"+this.getLkmGender()+"',");
    		sb.append("'1kmPhone':'"+this.getLkmPhone()+"',");
    		sb.append("'lkmMobile':'"+this.getLkmMobile()+"',");
    		sb.append("'lkmEmail':'"+this.getLkmEmail()+"',");
    		sb.append("'lkmPosition':'"+this.getLkmPosition()+"',");
    		sb.append("'lkmMemo':'"+this.getLkmMemo()+"'");
    		sb.append("}");
    		return sb.toString();
    	}
    }
    
  • 在映射配置文件中建立两个实体和两张表之间的关系

    在从表的配置文件中配置映射关系。

    <!-- 多对一的关系映射:
    	    	涉及的标签:<many-to-one/> 
    	    	标签的属性:
    	    		name:实体类中主表实体类的对象引用的名称(成员变量中主表实体类的对象名称)
    	    		class:主表类类名
    	    		column:指定该表中的外键名称-->
    <!--单向多对一:查询id的为1的联系人属性哪个客户
    	     select * cst_customer where cust_id = (select lkmId from cst_linkman where lkmId = 1); -->				
    <many-to-one name="customer" class = "Customer" column="lkm_cust_id"></many-to-one>
    	
    
    <?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 package="com.zwd.domain">
    	<class name="LinkMan" table="cst_linkman">
    		<id name="lkmId" column="lkmId">
    			<generator class="native"></generator> <!-- 指定主键生成方式 -->
    		</id>
    		<property name="lkmName" column="lkm_name"></property>
    		<property name="lkmGender" column="lkm_gender"></property>
    		<property name="lkmPhone" column="lkm_phone"></property>
    		<property name="lkmMobile" column="lkm_mobile"></property>
    		<property name="lkmEmail" column="lkm_email"></property>
    		<property name="lkmPosition" column="lkm_position"></property>
    		<property name="lkmMemo" column="lkm_memo"></property>
    	    
    	    <!-- 多对一的关系映射:
    	    			涉及的标签:<many-to-one/> 
    	    			标签的属性:
    	    				name:实体类中主表实体类的对象引用的名称(成员变量中主表实体类的对象名称)
    	    				class:主表类类名
    	    				column:指定该表中的外键名称-->
    	    <!--单向多对一:查询id的为1的联系人属性哪个客户
    	     select * cst_customer where cust_id = (select lkmId from cst_linkman where lkmId = 1); -->				
    	    <many-to-one name="customer" class = "Customer" column="lkm_cust_id"></many-to-one>
    	
    	</class>
    </hibernate-mapping>
    

    在主表映射的文件中添加配置

    		<!-- 一对多的关系映射:主表实体的映射配置
    			涉及的标签:
    				set:
    					作用:用于配置set集合属性
    					属性:
    						name:指定实体类中set集合的属性名称
    						table:指定从表的名称。在一对多配置时可以不写
    				key:
    					作用:用于映射外键字段
    					属性:
    						column:指定外键字段名称 
    				one-to-many:
    					作用:用于建立一对多的映射配置
    					属性:
    						class:用于指定从表实体的名称。-->
    		<!-- 单向一对多:查询id为1的客户对应哪些联系人
    			select * from cst_linkman where lkm_cust_id = 1 -->
                
    		<set name="linkmans" table="cst_linkman">
    			<key column="lkm_cust_id"></key>
    			<one-to-many class="LinkMan"/>
    		</set>
    
    <?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 package="com.zwd.domain">
    	<class name="Customer" table="cst_customer">
    		<id name="custId" column="cust_id">
    			<generator class="native"></generator> <!-- 指定主键生成方式 -->
    		</id>
    		<property name="custName" column="cust_name"></property>
    		<property name="custSource" column="cust_source"></property>
    		<property name="custIndustry" column="cust_industry"></property>
    		<property name="custLevel" column="cust_level"></property>
    		<property name="custAddress" column="cust_address"></property>
    		<property name="custPhone" column="cust_phone"></property>
    		
    		<!-- 一对多的关系映射:主表实体的映射配置
    			涉及的标签:
    				set:
    					作用:用于配置set集合属性
    					属性:
    						name:指定实体类中set集合的属性名称
    						table:指定从表的名称。在一对多配置时可以不写
    				key:
    					作用:用于映射外键字段
    					属性:
    						column:指定外键字段名称 
    				one-to-many:
    					作用:用于建立一对多的映射配置
    					属性:
    						class:用于指定从表实体的名称。-->
    		<set name="linkmans" table="cst_linkman">
    			<key column="lkm_cust_id"></key>
    			<one-to-many class="LinkMan"/>
    		</set>
    	</class>
    </hibernate-mapping>
    

4.一对多的CRUD操作

保存

  • 1、保存一个联系人,属于一个已存在的客户
/**
	 * 1、 保存一个联系人,属于一个已存在的客户
	 * 	正常保存:创建一个新的联系人,需要关联一个客户
	 */
	@Test
	public void test1(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		//1.查询一个客户
		Customer customer = session.get(Customer.class, 95);
		//2.创建一个新的联系人
		LinkMan linkMan = new LinkMan();
		linkMan.setLkmName("一对多的联系人1");
		//3.关联一个客户
		linkMan.setCustomer(customer);
		//4.保存一个联系人
		session.save(linkMan);
		tx.commit();
	}
  • 2、保存一个客户和一个联系人

    set标签的inverse属性:是否放弃维护关联关系的权利。ture:放弃;false:不放弃(默认值)

	/**
	 * 2、保存一个客户和一个联系人
	 * 		1.创建一个客户和一个联系人
	 * 		2.建立联系人和客户的双向关联关系
	 * 		3.使用符合原则的保存:先保存主表实体,再保存从表实体。
	 * 	上诉步骤还存在一个问题:我们保存两个实体,应该只有两条insert语句,
	 * 						 而执行结果却多了一条update语句。因为在保存客户时,会保存
	 * 						该客户所对应的联系人的信息,但此时联系人的id为空,当保存联系人后,
	 * 						联系人的id不为空,在commit的时候两个快照信息不一致,所以会有更新id语句
	 * 						会更新id是因为Customer.xml中的配置。
	 * 	解决办法:在Customer.xml中配置
	 * 			在set标签中添加inverse属性
	 * 			inverse:是否放弃维护关联关系的权利
	 * 				ture:放弃
	 * 				false:不放弃(默认值)
	 * 
	 */
	@Test
	public void test2(){
		//1.创建一个客户和一个联系人
		Customer customer = new Customer();
		customer.setCustName("一对多的客户2");
		LinkMan linkMan = new LinkMan();
		linkMan.setLkmName("一对多的联系人4");
		//2.建立联系人和客户的双向关联关系
		customer.getLinkmans().add(linkMan);
		linkMan.setCustomer(customer);
		
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//3.先保存主表实体,再保存从表实体。
		session.save(customer);
		session.save(linkMan);
		tx.commit();
	}
<set name="linkmans" table="cst_linkman" inverse="true">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
</set>
  • 3、级联保存:在实体类的配置中,在关系配置的地方使用 cascade属性,级联保存更新的取值:save-update

    cascade="save-update"
    

    1、级联保存–保存客户时级联保存该客户所对应的联系人

    	/**
    	 * 级联保存--保存客户时级联保存该客户所对应的联系人
    	 * 		首先需要在客户的配置文件中配置:
    	 * 			在set标签中使用cascade属性
    	 * 				cascade:配置级联操作
    	 * 				级联保存更新的取值:save-update
    	 * 		1、创建新的客户和新的联系人
    	 * 		2、建立客户和联系人之间的双向关系
    	 * 		3、保存客户并级联保存联系人
    	 */
    	@Test
    	public void test3(){
    		//1、创建新客户和新的联系人
    		Customer customer = new Customer();
    		LinkMan linkMan = new LinkMan();
    		customer.setCustName("一对多级联保存1");
    		linkMan.setLkmName("一对多级联保存1");
    		
    		//2、建立客户和联系人之间的双向关系
    		customer.getLinkmans().add(linkMan);
    		linkMan.setCustomer(customer);
    		
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		
    		//2、在保存客户时级联保存联系人
    		session.save(customer);
    		tx.commit();
    	}
    

    在客户实体类的配置文件中添加对级联的支持。

    	<set name="linkmans" table="cst_linkman" inverse="true" cascade="save-update">
    			<key column="lkm_cust_id"></key>
    			<one-to-many class="LinkMan"/>
    		</set>
    

    2、级联保存–保存联系人时级联保存该联系人所对应的客户

    	/**
    	 * 级联保存--保存联系人时级联保存该联系人所对应的客户
    	 * 		在联系人中使用cascade属性
    	 * 		1、创建新的客户和新的联系人
    	 * 		2、建立客户和联系人之间的双向关系
    	 * 		3、保存客户并级联保存联系人
    	 */
    	@Test
    	public void test4(){
    		//1、创建新客户和新的联系人
    		Customer customer = new Customer();
    		LinkMan linkMan = new LinkMan();
    		customer.setCustName("一对多级联保存2");
    		linkMan.setLkmName("一对多级联保存2");
    		
    		//2、建立客户和联系人之间的双向关系
    		customer.getLinkmans().add(linkMan);
    		linkMan.setCustomer(customer);
    		
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		
    		//2、在保存客户时级联保存联系人
    		session.save(linkMan);
    		tx.commit();
    	}
    

    在联系人实体类的配置文件中的配置。

     <many-to-one name="customer" class = "Customer" column="lkm_cust_id" cascade="save-update"></many-to-one>
    

更新:级联更新:

还是使用属性 cascade="save-update" :对一个对象的保存或更新操作会涉及它的关联对象的更新或保存。

Customer.xml中的配置。

<?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 package="com.zwd.domain">
	<class name="Customer" table="cst_customer">
		<id name="custId" column="cust_id">
			<generator class="native"></generator> <!-- 指定主键生成方式 -->
		</id>
		<property name="custName" column="cust_name"></property>
		<property name="custSource" column="cust_source"></property>
		<property name="custIndustry" column="cust_industry"></property>
		<property name="custLevel" column="cust_level"></property>
		<property name="custAddress" column="cust_address"></property>
		<property name="custPhone" column="cust_phone"></property>
		
		<!-- 一对多的关系映射:主表实体的映射配置
			涉及的标签:
				set:
					作用:用于配置set集合属性
					属性:
						name:指定实体类中set集合的属性名称
						table:指定从表的名称。在一对多配置时可以不写
				key:
					作用:用于映射外键字段
					属性:
						column:指定外键字段名称 
				one-to-many:
					作用:用于建立一对多的映射配置
					属性:
						class:用于指定从表实体的名称。-->
		<!-- 单向一对多:查询id为1的客户对应哪些联系人
						select * from cst_linkman where lkm_cust_id = 1 -->
		<set name="linkmans" table="cst_linkman" inverse="true" cascade="save-update">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
		</set>
	</class>
</hibernate-mapping>
/**
	 * 级联更新:
	 *  	创建一个新的联系人,查询一个客户
	 *  	建立联系人和客户之间的双向关系
	 *  	更新客户
	 */
	@Test
	public void test5(){
		//1、创建一个新的联系人
		LinkMan linkMan = new LinkMan();
		linkMan .setLkmName("级联更新3");
		
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//2、获取一个已存在的客户
		Customer customer = session.get(Customer.class, 95);
		//3、建立联系人与客户之间的双向关系
		customer.getLinkmans().add(linkMan);
		linkMan.setCustomer(customer);
		//4、更新客户
		session.update(customer);
		tx.commit();
	}

删除:级联删除

删除“多”的方相当于单表的删除。

删除“一”的方需要级联删除。

​ 需要在"一"的方中的配置文件配置级联删除。在Customer.xml中的配置,多个级联操作以逗号隔开。

<set name="linkmans" table="cst_linkman" cascade="save-update,delete">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
</set>

1、如果外键可以为null并且将关系的维护交给"一"的一方(在set中没有配置inverse=true),hibernate在删除"一"的方的数据时,会先更新该"一"所对应的"多"的外键值为null后,删除"多"方,再删除“一”方。

	/**
	 * 级联删除1:
	 * 		如果外键可以为null并且将关系的维护交给"一"的一方(在set中没有配置`inverse=true`),如果外键不允许为null并且也没有放弃维护关系的权利,则会报错,因为不能将外键值置为null。
	 * 		hibernate在删除"一"的方的数据时,会先更新该"一"所对应的"多"的外键值为null,然后再删除"一"方。
	 */
	@Test
	public void test6(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Customer customer = session.get(Customer.class, 96);
		session.delete(customer);
		tx.commit();
	}

执行结果:

Hibernate: update cst_linkman set lkm_cust_id=null where lkm_cust_id=?
Hibernate: delete from cst_linkman where lkmId=?
Hibernate: delete from cst_customer where cust_id=?

2、将维护关系的权利交给“多”的一方,Customer放弃维护关系的权利,在Customer.xml中配置 inverse = true

<set name="linkmans" table="cst_linkman" inverse="true" cascade="save-update,delete">
			<key column="lkm_cust_id"></key>
			<one-to-many class="LinkMan"/>
</set>
/**
	 * 级联删除2:
	 * 		将关系的维护交给“多”方,在Customer.xml中配置 inverse = true
	 * 		在删除主表记录时先删除字表的关联记录,然后再删除主表记录。
	 * 		
	 */
	@Test
	public void test7(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		
		Customer customer = session.get(Customer.class, 103);
		session.delete(customer);
		tx.commit();
	}

执行结果:

Hibernate: select customer0_.cust_id as cust_id1_0_0_, customer0_.cust_name as cust_nam2_0_0_, customer0_.cust_source as cust_sou3_0_0_, customer0_.cust_industry as cust_ind4_0_0_, customer0_.cust_level as cust_lev5_0_0_, customer0_.cust_address as cust_add6_0_0_, customer0_.cust_phone as cust_pho7_0_0_ from cst_customer customer0_ where customer0_.cust_id=?
    
Hibernate: select linkmans0_.lkm_cust_id as lkm_cust9_1_0_, linkmans0_.lkmId as lkmId1_1_0_, linkmans0_.lkmId as lkmId1_1_1_, linkmans0_.lkm_name as lkm_name2_1_1_, linkmans0_.lkm_gender as lkm_gend3_1_1_, linkmans0_.lkm_phone as lkm_phon4_1_1_, linkmans0_.lkm_mobile as lkm_mobi5_1_1_, linkmans0_.lkm_email as lkm_emai6_1_1_, linkmans0_.lkm_position as lkm_posi7_1_1_, linkmans0_.lkm_memo as lkm_memo8_1_1_, linkmans0_.lkm_cust_id as lkm_cust9_1_1_ from cst_linkman linkmans0_ where linkmans0_.lkm_cust_id=?
    
Hibernate: delete from cst_linkman where lkmId=?
Hibernate: delete from cst_customer where cust_id=?

查询:对象导航查询

​ hibernate的查询:OID查询、HQL查询、QBC查询、SQL查询、对象导航查询。

	/**
	 * 对象的导航查询:
	 * 		查询操作:OID查询、HQL查询、QBC查询、SQL查询。
	 * 		hibernate中的最后一种查询操作:对象导航查询。
	 * 			当我们通过调用get×××方法即可实现查询功能
	 */
	@Test
	public void test8(){
        Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//根据id获取一个customer对象
		Customer customer = session.get(Customer.class, 104);
		
		System.out.println(customer);
		//获取该用户下的所有联系人,第一次用到的时候才会查询保存在集合中
		Set<LinkMan> linkmans = customer.getLinkmans();//在此处不会去查询
		System.out.println(linkmans);//此处才会去数据库中查询
		
		tx.commit();
	}
	
	/**
	 * 获取当前联系人所对应的客户
	 */
	@Test
	public void test9(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//根据id获取联系人
		LinkMan linkMan = session.get(LinkMan.class,17L);
		
		System.out.println(linkMan);
		//查询当前联系人所对应的客户
		System.out.println(linkMan.getCustomer());
		
		tx.commit();
	}

lazy属性:

(1)class的lazy属性:它只管load方法是否是延迟加载。属性值:true(默认值)、false

(2)set标签以及many-to-one的lazy标签:它管的是关联对象是否是延迟加载,如果关联对象是延迟加载,则关联对象只有在第一次使用时才会使用。如果关联对象是立即加载,则当前对象加载时就会立即加载关联对象。

set标签中lazy的属性值:true(默认值)、false。

many-to-one标签中lazy的属性值:false、proxy(默认值)、no-proxy

set标签的lazy属性:一对多时,根据一的一方查询多的一方时,需要使用延迟加载。(默认配置即可)

<set name="linkmans" table="cst_linkman" inverse="true" cascade="save-update,delete"        lazy="false">
	<key column="lkm_cust_id"></key>
	<one-to-many class="LinkMan"/>
</set>
/**
	 * 查询id为105的客户下所有的联系人 customer.getLinkmans();
	 * 一对多时,根据一的一方查询多的一方时,需要使用延迟加载。(默认配置即可)
	 * 		延迟加载:
	 * 			customer = session.get(Customer.class, 104);//此处只查询客户
	 * 			Set<LinkMan> linkmans = customer.getLinkmans();//在此处不会去查询联系人
	 * 			System.out.println(linkmans);//此处才会去数据库中查询联系人
	 * 
	 * 如果需要改为立即加载:在customer.xml的set标签中添加 lazy=false
	 * 						set标签中的lazy属性的取值:
	 * 							true:延迟加载(默认取值);
	 * 							false:立即加载
	 * 		立即加载:
	 * 			customer = session.get(Customer.class, 104);//此处会立即查询客户以及客户的所有联系人,之后不再查询
	 */
	@Test
	public void test8(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//根据id获取一个customer对象
		Customer customer = session.get(Customer.class, 104);//延迟加载时:此处只查询客户
		
		System.out.println(customer);
		//获取该用户下的所有联系人,延迟加载时:第一次用到的时候才会查询保存在集合中
		Set<LinkMan> linkmans = customer.getLinkmans();//延迟加载时:在此处不会去查询联系人
		System.out.println(linkmans);//延迟加载时:此处才会去数据库中查询联系人
		
		tx.commit();
	}

many-to-one标签的lazy属性:多对一时,根据多的一方查询一的一方时,不需要使用延迟加载,而是立即加载,需要配置一下

<many-to-one name="customer" class = "Customer" lazy="false"
	    column="lkm_cust_id" cascade="save-update">
</many-to-one>
	
/**
	 * 查询id为17的联系人属于哪个客户
	 * 多对一时,根据多的一方查询一的一方时,不需要使用延迟加载,而是立即加载,需要配置一下
	 * 		many-to-one标签中的lazy属性的取值:
	 * 				false:立即加载;
	 * 	   proxy(默认值):看load方法是延迟加载还是立即加载,load方法默认是延迟加载。将load方法改                              为立即加载如下。
	 * 			 no-proxy:不管。
	 */
	@Test
	public void test9(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//根据id获取联系人
		LinkMan linkMan = session.get(LinkMan.class,17L);
		
		System.out.println(linkMan);
		//查询当前联系人所对应的客户
		Customer customer = linkMan.getCustomer();//在此处不会查询
		System.out.println(customer);//第一次使用时才查询(延迟加载)
		tx.commit();
	}

class标签的lazy属性:决定的是load方法是否是延迟加载

<class name="LinkMan" table="cst_linkman" lazy="false"> ....... </class>
	/**
	 * 将load方法改为立即加载
	 * 		在实体类的配置文件的class标签中添加 lazy属性。
	 * 		属性值:true:延迟加载
	 * 			   false:立即加载
	 * 
	 * class标签的lazy:它只能管load方法是否是延迟加载。
	 * set标签的lazy:它只管查询关联的集合对象是否是延迟加载。
	 * many-to-one的lazy:它管的是查询关联的主表实体是否立即加载。
	 */
	@Test
	public void test10(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		//根据id获取联系人
		LinkMan linkMan = session.load(LinkMan.class,17L);
		
		System.out.println(linkMan);
		Customer customer = linkMan.getCustomer();
		System.out.println(customer);
		tx.commit();
	}

5.多对多的映射操作

示例:用户和角色。

第一步:确立两张表之间的关系。

​ 一个用户对应多种角色。

​ 一个角色对应多个用户。

​ 所以角色和用户之间是多对多。

第二步:在数据库中实现两张表之间的关系

​ 在数据库中实现多对多要靠中间表。

​ 中间表中只能出现用户和角色主键。

第三步:在实体类中描述出两个实体之间的关系

第四步:在映射配置文件中建立两个实体和两张表之间的关系

  • 在实体类中描述出两个实体之间的关系

    用户表:SysUser.java

    //多对多关系映射:一个用户对应多个角色
    Set<SysRole> roles = new HashSet<SysRole>(0);
    
    package com.zwd.domain;
    
    import java.io.Serializable;
    import java.util.HashSet;
    import java.util.Set;
    
    public class SysUser implements Serializable{
    	
    	private long userId;
    	private String userName;
    	private String userPassWord;
    	
    	//多对多关系映射:一个用户对应多个角色
    	Set<SysRole> roles = new HashSet<SysRole>(0);
    	
    	public Set<SysRole> getRoles() {
    		return roles;
    	}
    	public void setRoles(Set<SysRole> roles) {
    		this.roles = roles;
    	}
    	public long getUserId() {
    		return userId;
    	}
    	public void setUserId(long userId) {
    		this.userId = userId;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	public String getUserPassWord() {
    		return userPassWord;
    	}
    	public void setUserPassWord(String userPassWord) {
    		this.userPassWord = userPassWord;
    	}
    	@Override
    	public String toString() {
    		return "SysUser [userId=" + userId + ", userName=" + userName + ", userPassWord=" + userPassWord + "]";
    	}
    }
    

    角色表:SysRole.java

    //多对多关系映射:一个角色对应多个用户
    Set<SysUser> users = new HashSet<SysUser>(0);
    
    package com.zwd.domain;
    
    import java.io.Serializable;
    import java.util.HashSet;
    import java.util.Set;
    
    public class SysRole implements Serializable{
    
    	private long roleId;
    	private String roleName;
    	private String roleMemo;
    	
    	//多对多关系映射:一个角色对应多个用户
    	Set<SysUser> users = new HashSet<SysUser>(0);
    	
    	public Set<SysUser> getUsers() {
    		return users;
    	}
    	public void setUsers(Set<SysUser> users) {
    		this.users = users;
    	}
    	public long getRoleId() {
    		return roleId;
    	}
    	public void setRoleId(long roleId) {
    		this.roleId = roleId;
    	}
    	public String getRoleName() {
    		return roleName;
    	}
    	public void setRoleName(String roleName) {
    		this.roleName = roleName;
    	}
    	public String getRoleMemo() {
    		return roleMemo;
    	}
    	public void setRoleMemo(String roleMemo) {
    		this.roleMemo = roleMemo;
    	}
    	@Override
    	public String toString() {
    		return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
    	}
    }
    
  • 在映射配置文件中建立两个实体和两张表之间的关系

    	        多对多的关系映射:
    				涉及的标签:
    					set:
    						作用:用于映射set集合属性
    						属性:
    							name:指定集合的名称
    							table:指定的是中间表的名称
    					key:
    						作用:用于映射外键字段。
    						属性:
    							column:指定的是当前实体在中间表的外键字段名称。
    					many-to-many:
    						作用:用于映射多对多的关系。
    						属性:
    							class:对方的实体类名称
    							column:对方在中间表的外键字段名称 
    

    SysUser.hbm.xml

            <set name="roles" table="user_role">
    			<key column="user_id"></key>
    			<many-to-many class="SysRole" column="role_id"></many-to-many>
    		</set>
    
    <?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 package="com.zwd.domain">
    	<class name="SysUser" table="sys_user">
    		<id name="userId" column="user_id">
    			<generator class="identity"></generator>
    		</id>
    
    		<property name="userName" column="user_name"></property>
    		<property name="userPassWord" column="user_password"></property>
    
    		<set name="roles" table="user_role">
    			<key column="user_id"></key>
    			<many-to-many class="SysRole" column="role_id"></many-to-many>
    		</set>
    	</class>
    </hibernate-mapping>    
    

    SysRole.hbm.xml

            <set name="users" table="user_role" >
    			<key column="role_id"></key>
    			<many-to-many class="SysUser" column="user_id"></many-to-many>
    		</set>
    
    <?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 package="com.zwd.domain">
    	<class name="SysRole" table="sys_role">
    		<id name="roleId" column="role_id">
    			<generator class="identity"></generator>
    		</id>
    	
    		<property name="roleName" column="role_name"></property>
    		<property name="roleMemo" column="role_password"></property>
    		
    		<!-- 多对多的关系映射:
    				涉及的标签:
    					set:
    						作用:用于映射set集合属性
    						属性:
    							name:指定集合的名称
    							table:指定的是中间表的名称
    					key:
    						作用:用于映射外键字段。
    						属性:
    							column:指定的是当前实体在中间表的外键字段名称。
    					many-to-many:
    						作用:用于映射多对多的关系。
    						属性:
    							class:对方的实体类名称
    							column:对方在中间表的外键字段名称 -->
    		<set name="users" table="user_role" >
    			<key column="role_id"></key>
    			<many-to-many class="SysUser" column="user_id"></many-to-many>
    		</set>
    	</class>
    </hibernate-mapping>    
    

    在Hibernate.cfg.xml中添加映射文件

            <!-- 3.配置映射文件的位置 -->
    		<mapping resource="com/zwd/domain/SysRole.hbm.xml"/>
    		<mapping resource="com/zwd/domain/SysUser.hbm.xml"/>
    

    逆向生成数据库表:sys_user、sys_role、user_role(只有两个外键,组成联合主键)

    public static void main(String[] args) {
    		getCurrentSession();
    	}
    

6.多对多的保存和删除操作

保存:

	/**
	 * 保存操作:
	 * 	需求:
	 * 		创建2个用户和3个角色
	 * 		让1号用户具备1号和2号角色
	 * 		让2号用户具备2号和3号角色
	 * 		保存用户和角色。
	 */
	@Test
	public void test1(){
		//1、创建用户和角色
		SysUser u1 = new SysUser();
		u1.setUserName("用户1");
		SysUser u2 = new SysUser();
		u2.setUserName("用户2");
		
		SysRole r1 = new SysRole();
		r1.setRoleName("角色1");
		SysRole r2 = new SysRole();
		r2.setRoleName("角色2");
		SysRole r3 = new SysRole();
		r3.setRoleName("角色3");
		
		//2、建立用户和角色之间的双向关系
		//先建立用户的
		u1.getRoles().add(r1);
		u1.getRoles().add(r2);
		
		u2.getRoles().add(r2);
		u2.getRoles().add(r3);
		//在建立角色的
		r1.getUsers().add(u1);
		r2.getUsers().add(u1);
		
		r2.getUsers().add(u2);
		r3.getUsers().add(u2);
		
		//3.保存:此处需要让多对多的关系中的其中任意一方放弃维护关系的权利。
		//			否则:user和role都会向关联表中插入记录
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		session.save(u1);
		session.save(u2);
		session.save(r1);
		session.save(r2);
		session.save(r3);
			
		tx.commit();
	}

删除:

    /**
	 * 删除操作:在项目中级联删除是禁止使用的
	 */
	@Test
	public void test2(){
		Session session = HibernateUtil.getCurrentSession();
		Transaction tx = session.beginTransaction();
		SysUser user = session.get(SysUser.class, 8l);
		session.delete(user);//配置级联删除
		
		tx.commit();
	}

Hibernate第四天-JPA

1、JPA概述

​ JPA:它是java persistence api,java持久化规范。

​ JPA通过JDK5.0 注解或XML描述对象-关系表的映射关系,并将运行期间的实体对象持久化到数据库中。

​ JPA是一套ORM规范,hibernate实现了JAP规范。

​ hibernate中有自己独立的ORM操作数据库的方式,也有JPA规范实现的操作数据库的方式。

2、JPA环境搭建

  • 创建java project项目,并导入jar包,required + jpa-metamodel-generator + 数据库驱动

  • 在src下创建 folder,META-INF;在META-INF下创建 persistence.xml

  • 增加persistence.xml配置文件中的提示。在hibernate的包中找到persistence_2_1.xsd的位置(\hibernate-release-5.3.9.Final\lib\jpa-metamodel-generator\hibernate-jpamodelgen-5.3.9.Final\persistence_2_1.xsd),Windows-preferences-XML Catalog,然后add,选择persistence_2_1.xsd的位置,key为http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd

  • persistence.xml导入约束:由于persistence_2_1.xsd会报错:找不到元素 ‘persistence’ 的声明,将2.1改为2.0解决问题。

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    			 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    			 			http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    			 version="2.0"
    			 >
    </persistence>
    			 
    
  • persistence.xml中的完整配置

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    			 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    			 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    			 					http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    			 version="2.0"
    			 >
    			 
    			 
    	<!-- 配置持久化单元,可以配置多个,但是名称不能重复。
    		name:用于指定持久化单元名称
    		transaction-type:指定事务类型
    			取值:
    				JTA: Java Transaction API (一般用于集群下的事务)
    				RESOURCE-LOCAL:指的是本地代码事务。(我们用这个)-->	
    	<persistence-unit name="myJPAUnit" transaction-type="RESOURCE_LOCAL">
    		<!-- JAP规范的提供商,可以不写 -->
    		<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    		<!-- 指定由JPA注解的实体类位置,可以不写 -->
    		<class>com.zwd.domain.Customer</class>
    		<!-- 连接数据库的相关配置,都是用hibernate的,所以只需把之前的hibernate主配置文件中的部分内容拷过来即可 -->
    		<properties>
    		
    		<property name="" value=""/>
    			<!-- 数据库方言 -->
    			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
    			<!-- 连接数据的信息 -->
    			<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
    			<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/spring"/>
    			<property name="hibernate.connection.username" value="root"/>
    			<property name="hibernate.connection.password" value="root"/>
    		
    			<!-- 2.Hibernate的可选配置 -->
    			
    			<!-- 配置数据库连接池 c3p0 :记得导c3p0的包(在hibernate包的option中)
    			<property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>-->
    			<!-- 是否生成sql语句打印 -->
    			<property name="hibernate.show_sql" value="true"/>
    			<!-- 是否格式化生成sql语句 -->
    			<property name="hibernate.format_sql" value="false"/>
    			<!-- 采用怎样的方式处理ddl -->
    			<property name="hibernate.hbm2ddl.auto" value="update"/>
    		
    		</properties>
    	</persistence-unit>
    </persistence>
    
  • 创建实体类Customer.java,并使用JPA的注解

    package com.zwd.domain;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /*******************************************************************************
     * javaBeans
     * cst_customer --> CstCustomer 
     * <table explanation>
     * @author 2019-08-16 10:45:34
     * 
     * 使用的注解都是使用JPA规范,都需要导入javax.persistence下的包
     */	
    @Entity//表明该类是一个实体类
    @Table(name="cst_customer")//建立当前类和数据库表的对应关系
    public class Customer implements java.io.Serializable {
    	@Id//表明当前字段是主键
    	@Column(name="cust_id")//表明对应数据库的主键字段是cust_id
    	@GeneratedValue(strategy=GenerationType.IDENTITY)//指定主键生产策略。strategy:使用JPA中提供的主键生产策略。此属性用不了。generator:可以使用hibernate中的主键生产策略。
    	private int custId;
    	
    	@Column(name="cust_name")
    	private String custName;
    	
    	@Column(name="cust_source")
    	private String custSource;
    	
    	@Column(name="cust_indestry")
    	private String custIndustry;
    	
    	@Column(name="cust_level")
    	private String custLevel;
    	
    	@Column(name="cust_address")
    	private String custAddress;
    	
    	@Column(name="cust_phone")
    	private String custPhone;
    	//method
    	public int getCustId() {
    		return custId;
    	}
    	public void setCustId(int custId) {
    		this.custId = custId;
    	}
    	public String getCustName() {
    		return custName;
    	}
    	public void setCustName(String custName) {
    		this.custName = custName;
    	}
    	public String getCustSource() {
    		return custSource;
    	}
    	public void setCustSource(String custSource) {
    		this.custSource = custSource;
    	}
    	public String getCustIndustry() {
    		return custIndustry;
    	}
    	public void setCustIndustry(String custIndustry) {
    		this.custIndustry = custIndustry;
    	}
    	public String getCustLevel() {
    		return custLevel;
    	}
    	public void setCustLevel(String custLevel) {
    		this.custLevel = custLevel;
    	}
    	public String getCustAddress() {
    		return custAddress;
    	}
    	public void setCustAddress(String custAddress) {
    		this.custAddress = custAddress;
    	}
    	public String getCustPhone() {
    		return custPhone;
    	}
    	public void setCustPhone(String custPhone) {
    		this.custPhone = custPhone;
    	}
    	//override toString Method 
    	public String toString() {
    		StringBuffer sb=new StringBuffer();
    		sb.append("{");
    		sb.append("'custId':'"+this.getCustId()+"',");
    		sb.append("'custName':'"+this.getCustName()+"',");
    		sb.append("'custSource':'"+this.getCustSource()+"',");
    		sb.append("'custIndustry':'"+this.getCustIndustry()+"',");
    		sb.append("'custLevel':'"+this.getCustLevel()+"',");
    		sb.append("'custAddress':'"+this.getCustAddress()+"',");
    		sb.append("'custPhone':'"+this.getCustPhone()+"'");
    		sb.append("}");
    		return sb.toString();
    	}
    }
    
  • 创建JPA的工具类:JPA的factory:EntityManagerFactory;JPA操作数据库的对象:EntityManager

    package com.zwd.uitls;
    
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    
    /**
     * JPA的工具类
     * @author Administrator
     *
     */
    public class JPAUtil {
    	//它就相当于sessionFactory
    	private static EntityManagerFactory factory;
    	
    	static{
    		factory = Persistence.createEntityManagerFactory("myJPAUnit");
    	}
    	
    	/**
    	 * 获取JPA操作数据库的对象
    	 * @return
    	 */
    	public static EntityManager CreateEntityManager(){
    		return factory.createEntityManager();
    	}
    	
    	public static void main(String[] args) {
    		CreateEntityManager();
    	}
    }
    

3、JPA的CRUD操作

保存:

entityManager.persist(c); 相当于save();

/**
	 * 1、保存:entityManager.persist(c);
	 */
	@Test
	public void test1(){
		//创建客户对象
		Customer c = new Customer();
		c.setCustName("JPA保存1");
		
		//1、获取EntityManager对象
		EntityManager entityManager = JPAUtil.CreateEntityManager();
		//2、获取事务,并开启
		EntityTransaction tx = entityManager.getTransaction();
		tx.begin();
		//3、操作数据库:保存
		entityManager.persist(c);
		//4、提交事务
		tx.commit();
		//5、关闭连接
		entityManager.close();
	}
  • 查询一个(立即加载): entityManager.find(Customer.class, 1); 相当于get();

       /**
    	 * 2、查询一个:entityManager.find(Customer.class, 1);
    	 */
    	@Test
    	public void test2(){
    		//1、获取EntityManager对象
    		EntityManager entityManager = JPAUtil.CreateEntityManager();
    		//2、获取事务,并开启
    		EntityTransaction tx = entityManager.getTransaction();
    		tx.begin();
    		//3、操作数据库:查询一个
    		Customer c = entityManager.find(Customer.class, 1);
    		System.out.println(c);
    		//4、提交事务
    		tx.commit();
    		//5、关闭连接
    		entityManager.close();
    	}
    
  • 查询一个(延迟加载): entityManager.getReference(Customer.class, 1); 相当于load();

    	
    	/**
    	 * 2、查询一个(延迟加载):entityManager.getReference(Customer.class, 1);----load()
    	 */
    	@Test
    	public void test2_1(){
    		//1、获取EntityManager对象
    		EntityManager entityManager = JPAUtil.CreateEntityManager();
    		//2、获取事务,并开启
    		EntityTransaction tx = entityManager.getTransaction();
    		tx.begin();
    		//3、操作数据库:查询一个(延迟加载)
    		Customer c = entityManager.getReference(Customer.class, 1);
    		System.out.println(c);
    		//4、提交事务
    		tx.commit();
    		//5、关闭连接
    		entityManager.close();
    	}
    

更新

  • 更新1: 更新1:在更改持久类的对象后,在tx.commit();时会自动更新数据库的记录

    	/**
    	 * 3、更新1:在更改持久类的对象后,在tx.commit();时会自动更新数据库的记录
    	 */
    	@Test
    	public void test3(){
    		//1、获取EntityManager对象
    		EntityManager entityManager = JPAUtil.CreateEntityManager();
    		//2、获取事务,并开启
    		EntityTransaction tx = entityManager.getTransaction();
    		tx.begin();
    		//3、操作数据库:查询一个后更新
    		Customer c = entityManager.find(Customer.class, 1);
    		c.setCustAddress("播州区");
    		//4、提交事务
    		tx.commit();
    		//5、关闭连接
    		entityManager.close();
    	}
    
  • 更新2: 更新2:entityManager.merge(c); 相当于update(); update如果遇到一级缓存已经包含了一个相同OID的对象会报错。merge则可以执行成功。

    	/**
    	 * 4、更新2:entityManager.merge(c);
    	 */
    	@Test
    	public void test4(){
    		//1、获取EntityManager对象
    		EntityManager entityManager = JPAUtil.CreateEntityManager();
    		//2、获取事务,并开启
    		EntityTransaction tx = entityManager.getTransaction();
    		tx.begin();
    		//3、操作数据库:查询一个后更新
    		Customer c = entityManager.find(Customer.class, 1);
    		c.setCustAddress("遵义市播州区");
    		//更新
    		entityManager.merge(c);
    		//4、提交事务
    		tx.commit();
    		//5、关闭连接
    		entityManager.close();
    	}
    
    @Test
    	public void test(){
    		Session session = HibernateUtil.getSession();
    		Transaction tx = session.beginTransaction();
    		
    		Customer c1 = session.get(Customer.class, 3);
    		tx.commit();
    		session.close();//关闭
    		//修改客户信息
    		c1.setCustName("JPA1");//托管态
    		
    		Session session1 = HibernateUtil.getSession();
    		Transaction tx1 = session1.beginTransaction();
    		
    		//再次查询客户
    		Customer c2 = session1.get(Customer.class, 3);
    		//更新修改对象:
    		/**此处应该使用merge:因为session1中已经存在id为2的Customer对象c2,
    		  *当托管态的c1进入session1时,因为c1和c2的内容不一样,
    		  *所以当c1进入session1中时会被认为是不同的对象,但是ID又一样,所以使用update会报错:session中存在具有相同ID的不同对象
    		  *使用merge将会合并两对象的内容,并更新c2的内容。
    		*/
    		//session1.update(c1);//将托管态转为持久态
    		session1.merge(c1);
    		tx1.commit();
    		session1.close();
    	}
    

删除:

entityManager.remove(c); 相当于delete();

   /**
	 * 5、删除:entityManager.remove(c);
	 */
	@Test
	public void test5(){
		//1、获取EntityManager对象
		EntityManager entityManager = JPAUtil.CreateEntityManager();
		//2、获取事务,并开启
		EntityTransaction tx = entityManager.getTransaction();
		tx.begin();
		//3、操作数据库:查询一个后删除(需要把要删除对象查询出来)
		Customer c = entityManager.find(Customer.class, 1);
		//更新
		entityManager.remove(c);
		//4、提交事务
		tx.commit();
		//5、关闭连接
		entityManager.close();
	} 

查询所有:

      		涉及的对象:JPA的Query
	  		如何获取该对象:entityManager.createQuery(String jpql);
	  		参数含义:
	  			jpql:java persistence query language
	  			它的写法和HQL很相似,也是把表名换成类名,将字段名换成属性名。
	  			它在写查询所有时,不能直接用 from 实体类,
	  			需要使用select关键字:select c from Customer c(也不能使用select *
	/**
	 * 6、查询所有:
	 * 		涉及的对象:JPA的Query
	 * 		如何获取该对象:entityManager.createQuery(String jpql);
	 * 		参数含义:
	 * 			jpql:java persistence query language
	 * 			它的写法和HQL很相似,也是把表名换成类名,将字段名换成属性名。
	 * 			它在写查询所有时,不能直接用 from 实体类,
	 * 			需要使用select关键字:select c from Customer c(也不能使用select *)
	 */
	@Test
	public void test6(){
		//1、获取EntityManager对象
		EntityManager entityManager = JPAUtil.CreateEntityManager();
		//2、获取事务,并开启
		EntityTransaction tx = entityManager.getTransaction();
		tx.begin();
		//3、操作数据库:查询所有
		//Query query = entityManager.createQuery("select c from Customer c");
		Query query = entityManager.createQuery("select c from Customer c where custId = ?2 and custName like ?3");
		query.setParameter(2, 2);
		query.setParameter(3, "%JPA%");
		//获取数据集
		List resultList = query.getResultList();
		for (Object object : resultList) {
			System.out.println(object);
		}
		//4、提交事务
		tx.commit();
		//5、关闭连接
		entityManager.close();
	}

4、JPA中的一对多关系映射操作

  • 客户实体类:Customer.java
//一对多的映射,一的一方:一个客户包含多个联系人
	@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.ALL,
               fetch=FetchType.EAGER)
private Set<LinkMan> linkMans = new HashSet<LinkMan>(0);

//mappedBy="customer":表明Customer放弃维护关系的权利
//cascade=CascadeType.ALL:级联操作
//fetch=FetchType.EAGER:立即加载关联对象
	
package com.zwd.domain;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/*******************************************************************************
 * javaBeans
 * cst_customer --> CstCustomer 
 * <table explanation>
 * @author 2019-08-16 10:45:34
 * 
 * 使用的注解都是使用JPA规范,都需要导入javax.persistence下的包
 */	
@Entity//表明该类是一个实体类
@Table(name="cst_customer")//建立当前类和数据库表的对应关系
public class Customer implements java.io.Serializable {
	@Id//表明当前字段是主键
	@Column(name="cust_id")//表明对应数据库的主键字段是cust_id
	@GeneratedValue(strategy=GenerationType.IDENTITY)//指定主键生产策略。strategy:使用JPA中提供的主键生产策略。此属性用不了。generator:可以使用hibernate中的主键生产策略。
	private int custId;
	
	@Column(name="cust_name")
	private String custName;
	
	@Column(name="cust_source")
	private String custSource;
	
	@Column(name="cust_indestry")
	private String custIndustry;
	
	@Column(name="cust_level")
	private String custLevel;
	
	@Column(name="cust_address")
	private String custAddress;
	
	@Column(name="cust_phone")
	private String custPhone;
	
	//一对多的映射,一的一方:一个客户包含多个联系人
	@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
	private Set<LinkMan> linkMans = new HashSet<LinkMan>(0);
	
	//method
	public Set<LinkMan> getLinkMans() {
		return linkMans;
	}
	public void setLinkMans(Set<LinkMan> linkMans) {
		this.linkMans = linkMans;
	}
	public int getCustId() {
		return custId;
	}
	public void setCustId(int custId) {
		this.custId = custId;
	}
	public String getCustName() {
		return custName;
	}
	public void setCustName(String custName) {
		this.custName = custName;
	}
	public String getCustSource() {
		return custSource;
	}
	public void setCustSource(String custSource) {
		this.custSource = custSource;
	}
	public String getCustIndustry() {
		return custIndustry;
	}
	public void setCustIndustry(String custIndustry) {
		this.custIndustry = custIndustry;
	}
	public String getCustLevel() {
		return custLevel;
	}
	public void setCustLevel(String custLevel) {
		this.custLevel = custLevel;
	}
	public String getCustAddress() {
		return custAddress;
	}
	public void setCustAddress(String custAddress) {
		this.custAddress = custAddress;
	}
	public String getCustPhone() {
		return custPhone;
	}
	public void setCustPhone(String custPhone) {
		this.custPhone = custPhone;
	}
	//override toString Method 
	public String toString() {
		StringBuffer sb=new StringBuffer();
		sb.append("{");
		sb.append("'custId':'"+this.getCustId()+"',");
		sb.append("'custName':'"+this.getCustName()+"',");
		sb.append("'custSource':'"+this.getCustSource()+"',");
		sb.append("'custIndustry':'"+this.getCustIndustry()+"',");
		sb.append("'custLevel':'"+this.getCustLevel()+"',");
		sb.append("'custAddress':'"+this.getCustAddress()+"',");
		sb.append("'custPhone':'"+this.getCustPhone()+"'");
		sb.append("}");
		return sb.toString();
	}
}
  • 联系人实体类:LinkMan.java

    //一对多关系映射:多的一方
    	//从表的实体类应该包含主表实体类的对象引用。
        @ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY)
        @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
    	private Customer customer;
    
    // @JoinColumn:为联系人实体类添加外键
    
    package com.zwd.domain;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.FetchType;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.ManyToOne;
    import javax.persistence.Table;
    
    /*******************************************************************************
     * javaBeans
     * cst_linkman --> CstLinkman 
     * <table explanation>
     * @author 2019-08-12 21:30:10
     * 
     */	
    @Entity
    @Table(name="cst_linkman")
    public class LinkMan implements java.io.Serializable {
    	
    	/** 联系人编号(主键) **/
        @Id
        @Column(name="lkm_id")
        @GeneratedValue(strategy=GenerationType.IDENTITY)
    	private long lkmId;
        
    	/** 联系人姓名 **/
        @Column(name="lkm_name")
    	private String lkmName;
        
    	/** 联系人性别 **/
        @Column(name="lkm_gender")
    	private String lkmGender;
        
    	/** 联系人办公电话 **/
        @Column(name="lkm_phone")
    	private String lkmPhone;
        
    	/** 联系人手机 **/
        @Column(name="lkm_mobile")
    	private String lkmMobile;
        
    	/** 联系人邮箱 **/
        @Column(name="lkm_email")
    	private String lkmEmail;
    	/** 联系人职位 **/
        
        @Column(name="lkm_position")
    	private String lkmPosition;
        
    	/** 联系人备注 **/
        @Column(name="lkm_memo")
    	private String lkmMemo;
    	
    	//一对多关系映射:多的一方
    	//从表的实体类应该包含主表实体类的对象引用。
        @ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY)
        @JoinColumn(name="lkm_cust_id",referencedColumnName="cust_id")
    	private Customer customer;
    	
    	public Customer getCustomer() {
    		return customer;
    	}
    	public void setCustomer(Customer customer) {
    		this.customer = customer;
    	}
    	//method
    	public long getLkmId() {
    		return lkmId;
    	}
    	public void setLkmId(long lkmId) {
    		this.lkmId = lkmId;
    	}
    	public String getLkmName() {
    		return lkmName;
    	}
    	public void setLkmName(String lkmName) {
    		this.lkmName = lkmName;
    	}
    	public String getLkmGender() {
    		return lkmGender;
    	}
    	public void setLkmGender(String lkmGender) {
    		this.lkmGender = lkmGender;
    	}
    	public String getLkmPhone() {
    		return lkmPhone;
    	}
    	public void setLkmPhone(String lkmPhone) {
    		this.lkmPhone = lkmPhone;
    	}
    	public String getLkmMobile() {
    		return lkmMobile;
    	}
    	public void setLkmMobile(String lkmMobile) {
    		this.lkmMobile = lkmMobile;
    	}
    	public String getLkmEmail() {
    		return lkmEmail;
    	}
    	public void setLkmEmail(String lkmEmail) {
    		this.lkmEmail = lkmEmail;
    	}
    	public String getLkmPosition() {
    		return lkmPosition;
    	}
    	public void setLkmPosition(String lkmPosition) {
    		this.lkmPosition = lkmPosition;
    	}
    	public String getLkmMemo() {
    		return lkmMemo;
    	}
    	public void setLkmMemo(String lkmMemo) {
    		this.lkmMemo = lkmMemo;
    	}
    	//override toString Method 
    	public String toString() {
    		StringBuffer sb=new StringBuffer();
    		sb.append("{");
    		sb.append("'1kmId':'"+this.getLkmId()+"',");
    		sb.append("'lkmName':'"+this.getLkmName()+"',");
    		sb.append("'lkmGender':'"+this.getLkmGender()+"',");
    		sb.append("'1kmPhone':'"+this.getLkmPhone()+"',");
    		sb.append("'lkmMobile':'"+this.getLkmMobile()+"',");
    		sb.append("'lkmEmail':'"+this.getLkmEmail()+"',");
    		sb.append("'lkmPosition':'"+this.getLkmPosition()+"',");
    		sb.append("'lkmMemo':'"+this.getLkmMemo()+"'");
    		sb.append("}");
    		return sb.toString();
    	}
    }
    

保存:

此时只需要配置谁拥有维护关系的权利即可。mappedBy="customer":表明Customer放弃维护关系的权利

	/**
	 * 1、保存操作:在Customer中配置mappedBy="customer"
	 * 		创建新的客户和联系人
	 * 		建立双向的关联关系
	 * 		保存
	 */
	@Test
	public void test1(){
		//创建新的客户和联系人
		Customer c = new Customer();
		LinkMan l = new LinkMan();
		c.setCustName("JPA One To Many customer");
		l.setLkmName("JPA One To Many linkMan");
		//建立双向关联关系
		c.getLinkMans().add(l);
		l.setCustomer(c);
		
		EntityManager em = JPAUtil.CreateEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		//保存
		em.persist(c);
		em.persist(l);
		
		tx.commit();
		em.close();
	}

更新:

在更新客户的时候同时保存联系人。在客户的关系中配置 cascade=CascadeType.PERSIST

	/**
	 * 级联更新:在Customer中配置cascade=CascadeType.PERSIST
	 * 		新建一个联系人,查询一个客户
	 * 		为该客户分配联系人
	 * 		更新客户
	 */
	@Test
	public void test2(){
		//创建新的客户和联系人
		LinkMan l = new LinkMan();
		l.setLkmName("JPA One To Many linkMan2");
		
		EntityManager em = JPAUtil.CreateEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		Customer c = em.find(Customer.class, 4);
		//建立双向关联关系
		c.getLinkMans().add(l);
		l.setCustomer(c);
		em.merge(c);//级联更新,在更新客户的同时保存联系人
		tx.commit();
		em.close();
	}

删除:

删除一的方需要级联删除:在客户的关系中配置:cascade=CascadeType.REMOVE/ALL

	/**
	 * 删除:
	 * 		在删除多的一方相当于单表操作。
	 * 		在删除一的一方需要级联操作。
	 * 		在客户中配置: cascade=CascadeType.REMOVE/ALL
	 */
	@Test
	public void test3(){
		EntityManager em = JPAUtil.CreateEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		Customer c = em.find(Customer.class, 7);
		//级联删除:@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.ALL)
		em.remove(c);
		tx.commit();
		em.close();
	}

查询

  • 查询一的方

    	/**
    	 * 查询一的方(find),多的方默认为延迟加载:先查询客户,然后根据客户获取联系人
    	 * 默认情况:
    	 * 		在find客户时只查询客户,在get联系人对象时,在第一次用到的联系人对象时才查询
    	 * 也可以将联系人的查询改为立即查询(在find客户时就查询联系人)
    	 * 		在客户的联系人属性中配置 :fetch=FetchType.EAGER
    	 * 		@OneToMany(targetEntity=LinkMan.class,mappedBy="customer",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
    	 */
    	@Test
    	public void test4(){
    		EntityManager em = JPAUtil.CreateEntityManager();
    		EntityTransaction tx = em.getTransaction();
    		tx.begin();
    		
    		Customer c = em.find(Customer.class, 8);
    		System.out.println(c);
    		Set<LinkMan> linkMans = c.getLinkMans();
    		System.out.println(linkMans);
    		
    		tx.commit();
    		em.close();
    	}
    
  • 查询多的方:

    	/**
    	 * 查询多的方(find),一的方默认为立即加载:先查询联系人,然后根据联系获取客户
    	 * 默认情况:在find联系人时会立即查询客户
    	 * 也可以改为延迟加载:
    	 * 		在联系人的关系映射中配置:   @ManyToOne(targetEntity=Customer.class,fetch=FetchType.LAZY)
    	 */
    	@Test
    	public void test5(){
    		EntityManager em = JPAUtil.CreateEntityManager();
    		EntityTransaction tx = em.getTransaction();
    		tx.begin();
    		
    		LinkMan l = em.find(LinkMan.class, 6l);
    		System.out.println(l);
    		Customer c = l.getCustomer();
    		System.out.println(c);
    		
    		tx.commit();
    		em.close();
    	}
    

5、JPA中的多对多映射操作

案例:用户和角色

  • 用户:SysUser.java

        //多对多关系映射:一个用户对应多个角色
    	@ManyToMany(mappedBy="users",cascade=CascadeType.ALL)//多对多关系,user放弃维护关系的权利
    	Set<SysRole> roles = new HashSet<SysRole>(0);
    

    JAP中主键生产的两种方式:

    	@Id
    	@Column(name="user_id")
    //	@GenericGenerator(name="aa",strategy="identity")//指定一个hibernate的主键生产器
    //	@GeneratedValue(generator="aa")//用hibernate的生成器
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	private long userId;
    
    package com.zwd.domain;
    
    import java.io.Serializable;
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.ManyToMany;
    import javax.persistence.Table;
    
    import org.hibernate.annotations.GenericGenerator;
    @Entity
    @Table(name="sys_user")
    public class SysUser implements Serializable{
    	
    	@Id
    	@Column(name="user_id")
    //	@GenericGenerator(name="aa",strategy="identity")//指定一个hibernate的主键生产器
    //	@GeneratedValue(generator="aa")//用hibernate的生成器
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	private long userId;
    	
    	@Column(name="user_name")
    	private String userName;
    	
    	@Column(name="user_password")
    	private String userPassWord;
    	
    	//多对多关系映射:一个用户对应多个角色
    	@ManyToMany(mappedBy="users",cascade=CascadeType.ALL)//多对多关系,user放弃维护关系的权利
    	Set<SysRole> roles = new HashSet<SysRole>(0);
    	
    	public Set<SysRole> getRoles() {
    		return roles;
    	}
    	public void setRoles(Set<SysRole> roles) {
    		this.roles = roles;
    	}
    	public long getUserId() {
    		return userId;
    	}
    	public void setUserId(long userId) {
    		this.userId = userId;
    	}
    	public String getUserName() {
    		return userName;
    	}
    	public void setUserName(String userName) {
    		this.userName = userName;
    	}
    	public String getUserPassWord() {
    		return userPassWord;
    	}
    	public void setUserPassWord(String userPassWord) {
    		this.userPassWord = userPassWord;
    	}
    	@Override
    	public String toString() {
    		return "SysUser [userId=" + userId + ", userName=" + userName + ", userPassWord=" + userPassWord + "]";
    	}
    }
    
  • 角色:SysRole.java

    //多对多关系映射:一个角色对应多个用户
    @ManyToMany(cascade=CascadeType.ALL)//多对多:role需要维护关系
    //加入一张表
    @JoinTable(name="user_role_ref",//表名
    			joinColumns = {@JoinColumn(name="role_id",referencedColumnName="role_id")},//当前实体类在中间表中的外键字段
    			inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")})//对方实体类在中间表中的外键字段
    	Set<SysUser> users = new HashSet<SysUser>(0);
    
    package com.zwd.domain;
    
    import java.io.Serializable;
    import java.util.HashSet;
    import java.util.Set;
    
    import javax.persistence.CascadeType;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.JoinColumn;
    import javax.persistence.JoinTable;
    import javax.persistence.ManyToMany;
    import javax.persistence.Table;
    
    import org.hibernate.annotations.GenericGenerator;
    @Entity
    @Table(name="sys_role")
    public class SysRole implements Serializable{
    
    	@Id
    	@Column(name="role_id")
    	//@GenericGenerator(name="aa",strategy="identity")
    	//@GeneratedValue(generator="aa")
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	private long roleId;
    	
    	@Column(name="role_name")
    	private String roleName;
    	
    	@Column(name="role_memo")
    	private String roleMemo;
    	
    	//多对多关系映射:一个角色对应多个用户
    	@ManyToMany(cascade=CascadeType.ALL)//多对多:role需要维护关系
    	//加入一张表
    	@JoinTable(name="user_role_ref",//表名
    				joinColumns = {@JoinColumn(name="role_id",referencedColumnName="role_id")},//当前实体类在中间表中的外键字段
    			    inverseJoinColumns={@JoinColumn(name="user_id",referencedColumnName="user_id")})//对方实体类在中间表中的外键字段
    	Set<SysUser> users = new HashSet<SysUser>(0);
    	
    	public Set<SysUser> getUsers() {
    		return users;
    	}
    	public void setUsers(Set<SysUser> users) {
    		this.users = users;
    	}
    	public long getRoleId() {
    		return roleId;
    	}
    	public void setRoleId(long roleId) {
    		this.roleId = roleId;
    	}
    	public String getRoleName() {
    		return roleName;
    	}
    	public void setRoleName(String roleName) {
    		this.roleName = roleName;
    	}
    	public String getRoleMemo() {
    		return roleMemo;
    	}
    	public void setRoleMemo(String roleMemo) {
    		this.roleMemo = roleMemo;
    	}
    	@Override
    	public String toString() {
    		return "SysRole [roleId=" + roleId + ", roleName=" + roleName + ", roleMemo=" + roleMemo + "]";
    	}
    }
    

保存:

	/**
	 * 1、保存:	 
	 * 		创建两个用户
	 * 		创建三个角色
	 * 		让1号用户具备1号和2号角色
	 * 		让2号用户具备2号和3号角色
	 * 可以一个一个保存:
	 * 			em.persist(u1);
		        em.persist(u2);
		        em.persist(r1);
		        em.persist(r2);
		        em.persist(r3);
	    也可以级联保存:在双向关系中配置:cascade=CascadeType.PERSIST

	 */
	@Test
	public void test1(){
		//创建用户和角色
		SysUser u1 = new SysUser();
		SysUser u2 = new SysUser();
		
		SysRole r1 = new SysRole();
		SysRole r2 = new SysRole();
		SysRole r3 = new SysRole();
		
		u1.setUserName("JPA Many To Many u1");
		u2.setUserName("JPA Many To Many u2");
		
		r1.setRoleName("JPA Many To Many r1");
		r2.setRoleName("JPA Many To Many r2");
		r3.setRoleName("JPA Many To Many r3");
		//建立用户和角色的双向关联关系
		u1.getRoles().add(r1);
		u1.getRoles().add(r2);
		u2.getRoles().add(r2);
		u2.getRoles().add(r3);
		
		r1.getUsers().add(u1);
		r2.getUsers().add(u1);
		r2.getUsers().add(u2);
		r3.getUsers().add(u2);
		
		EntityManager em = JPAUtil.CreateEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();
		//保存操作
//		em.persist(u1);
//		em.persist(u2);
//		em.persist(r1);
//		em.persist(r2);
//		em.persist(r3);
		
		//级联保存
		em.persist(u1);
		
		tx.commit();
		em.close();
	}

删除:

	/**
	 * 级联删除:无论在hibernate还是在JPA中都不允许
	 * 			cascade=CascadeType.ALL
	 */
	@Test
	public void test2(){
		EntityManager em = JPAUtil.CreateEntityManager();
		EntityTransaction tx = em.getTransaction();
		tx.begin();

		SysUser user = em.find(SysUser.class,1l);
		em.remove(user);
		
		tx.commit();
		em.close();
	}

6、在JPA中使用c3p0连接池

  • 导c3p0的jar包

  • 配置persistence.xml

    	<!-- 配置数据库连接池 c3p0 :记得导c3p0的包(在hibernate包的option中)-->
    <property name="hibernate.connection.provider_class" value="org.hibernate.connection.C3P0ConnectionProvider"/>
    		
    
    /**
    	 * 验证c3p0的配置是否可用
    	 */
    	@Test
    	public void test3(){
    		EntityManager em = JPAUtil.CreateEntityManager();
    		Session session = em.unwrap(Session.class);
    		session.doWork(new Work(){
    			@Override
    			public void execute(Connection conn) throws SQLException {
    				System.out.println(conn.getClass().getName());
    			}
    		});
    	}
    

7、使用JPA的注解配置,使用hibernate的xml配置文件和操作

  • Customer.java: 不使用hibernate的映射配置,使用JPA的注解配置

    package com.zwd.domain;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    /*******************************************************************************
     * javaBeans
     * cst_customer --> Customer 
     * <table explanation>
     * @author 2019-08-12 14:43:39
     * 
     */	
    @Entity
    @Table(name="cst_customer")
    public class Customer implements java.io.Serializable {
    	@Id
    	@Column(name="cust_id")
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	private int custId;
    	
    	@Column(name="cust_name")
    	private String custName;
    	
    	@Column(name="cust_source")
    	private String custSource;
    	
    	@Column(name="cust_industry")
    	private String custIndustry;
    	
    	@Column(name="cust_level")
    	private String custLevel;
    	
    	@Column(name="cust_address")
    	private String custAddress;
    	
    	@Column(name="cust_phone")
    	private String custPhone;
    	
    	//method
    	public int getCustId() {
    		return custId;
    	}
    	public void setCustId(int custId) {
    		this.custId = custId;
    	}
    	public String getCustName() {
    		return custName;
    	}
    	public void setCustName(String custName) {
    		this.custName = custName;
    	}
    	public String getCustSource() {
    		return custSource;
    	}
    	public void setCustSource(String custSource) {
    		this.custSource = custSource;
    	}
    	public String getCustIndustry() {
    		return custIndustry;
    	}
    	public void setCustIndustry(String custIndustry) {
    		this.custIndustry = custIndustry;
    	}
    	public String getCustLevel() {
    		return custLevel;
    	}
    	public void setCustLevel(String custLevel) {
    		this.custLevel = custLevel;
    	}
    	public String getCustAddress() {
    		return custAddress;
    	}
    	public void setCustAddress(String custAddress) {
    		this.custAddress = custAddress;
    	}
    	public String getCustPhone() {
    		return custPhone;
    	}
    	public void setCustPhone(String custPhone) {
    		this.custPhone = custPhone;
    	}
    	//override toString Method 
    	public String toString() {
    		StringBuffer sb=new StringBuffer();
    		sb.append("{");
    		sb.append("'custId':'"+this.getCustId()+"',");
    		sb.append("'custName':'"+this.getCustName()+"',");
    		sb.append("'custSource':'"+this.getCustSource()+"',");
    		sb.append("'custIndustry':'"+this.getCustIndustry()+"',");
    		sb.append("'custLevel':'"+this.getCustLevel()+"',");
    		sb.append("'custAddress':'"+this.getCustAddress()+"',");
    		sb.append("'custPhone':'"+this.getCustPhone());
    		sb.append("}");
    		return sb.toString();
    	}
    }
    
  • Hibernate.cfg.xml :配置映射文件时写成类,其他不变

    	<!-- 3.配置映射文件的位置 -->
    		<!-- <mapping resource="com/zwd/domain/Customer.xml" />
    		<mapping resource="com/zwd/domain/LinkMan.xml" /> -->
    		<mapping class="com.zwd.domain.Customer"/>
    
    <?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>
    		<!-- 1.配置连接的数据库信息 -->
    		
    		<!-- 数据库方言 -->
    		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    		<!-- 连接数据的信息 -->
    		<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    		<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/spring</property>
    		<property name="hibernate.connection.username">root</property>
    		<property name="hibernate.connection.password">root</property>
    		
    		<!-- 2.Hibernate的可选配置 -->
    		
    		<!-- 配置数据库连接池 c3p0 :记得导c3p0的包(在hibernate包的option中)-->
    		<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
    		<!-- 配置session与线程绑定 -->
    		<property name="hibernate.current_session_context_class">thread</property>
    		<!-- 是否生成sql语句打印 -->
    		<property name="hibernate.show_sql">true</property>
    		<!-- 是否格式化生成sql语句 -->
    		<property name="hibernate.format_sql">false</property>
    		<!-- 采用怎样的方式处理ddl -->
    		<property name="hibernate.hbm2ddl.auto">update</property>
    		
    		<!-- 3.配置映射文件的位置 -->
    		<!-- <mapping resource="com/zwd/domain/Customer.xml" />
    		<mapping resource="com/zwd/domain/LinkMan.xml" /> -->
    		<mapping class="com.zwd.domain.Customer"/>
    		
    	</session-factory>
    </hibernate-configuration>
    
  • 对数据库的操作使用hibernate的操作

    package com.zwd.test;
    
    import org.hibernate.Session;
    import org.hibernate.Transaction;
    import org.junit.Test;
    
    import com.zwd.domain.Customer;
    import com.zwd.utils.HibernateUtil;
    
    /**
     * 使用JPA的注解,hibernate的配置文件和操作
     * @author Administrator
     *
     */
    public class HibernateDemo1 {
    
    	/**
    	 * 保存
    	 */
    	@Test
    	public void test1(){
    		Customer c = new Customer();
    		c.setCustName("JPA Hibernate 保存");
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		session.save(c);
    		tx.commit();
    	}
    	/**
    	 * 查询一个
    	 */
    	@Test
    	public void test2(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		Customer customer = session.find(Customer.class, 9);
    		System.out.println(customer);
    		tx.commit();
    	}
    	/**
    	 * 更新
    	 */
    	@Test
    	public void test3(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		Customer customer = session.find(Customer.class, 9);
    		customer.setCustPhone("123455");
    		session.update(customer);
    		tx.commit();
    	}
    	
    	/**
    	 * 删除
    	 */
    	@Test
    	public void test4(){
    		Session session = HibernateUtil.getCurrentSession();
    		Transaction tx = session.beginTransaction();
    		Customer customer = session.find(Customer.class, 9);
    		session.delete(customer);
    		tx.commit();
    	}
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值