Hibernate剩余部分整理

一、表关系转映射文件

1.一对多关系

1.1映射文件配置

在映射文件中一的一方使用< 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.zgf.entity" >
	<class name="Customer" table="tb_cst_customer" >
		<id name="cust_id"  >
			<generator class="native"></generator>
		</id>
		<property name="cust_name" column="cust_name" ></property>
		...
		<!-- 配置一对多关系 -->
		<!-- 
			name:多的一方集合的属性名称
			即Customer类中的集合的属性名
			private Set<LinkMan> linkMens= new HashSet<LinkMan>();
		 -->
		<set name="linkMens">
			<!-- 
				key标签
					column:多的一方外键的名称
			 -->
			<key column="lkm_cust_id"></key>
			<!--
				one-to-many
					class:多的一方类的全路径名
					 由于上面配置<hibernate-mapping package="com.zgf.entity" >
					 SaleVisit类属于此路径下的类可以直接写类名
			 -->
			<one-to-many class="LinkMan"/>
		</set>
	</class>
</hibernate-mapping>

在多的一方映射文件中使用< 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.zgf.entity" >
	<class name="LinkMan" table="tb_cst_linkman" >
		<id name="lkm_id"  >
			<generator class="uuid"></generator>
		</id>
		......
		
		<!-- 多对一 -->
		<!-- 
			many-to-one
				name:SaleVisit类中引用一的一方对象的属性名
					private Customer customer;
				column:表中外键的名称
				class:引用一的一方类的全路径
					由于配置<hibernate-mapping package="com.zgf.entity" >
					且SaleVisit与Customer在同一包下,只需要写类名即可
		 -->
		<many-to-one name="customer" column="lkm_cust_id" class="Customer" />
		
	</class>
</hibernate-mapping>
1.2级联操作

当以Customer对象为主控方,级联操作Customer对象以及LinkMan对象时,需要在Customer对应的映射文件< set>上配置cascade属性值,这样可以减少代码量。简化操作一定要使用save-update,不建议使用delete。

		<!-- 
			cascade:可取值save-update(级联保存或修改)、delete(级联删除)、all(delete,save-update)
		 -->
		<set name="linkMens" cascade="save-update">
			
			<key column="lkm_cust_id"></key>
		
			<one-to-many class="LinkMan"/>
		</set>
1.3关系维护

在保存时,两方都会维护外键关系,关系维护两次,一次时在保存LinkMan时,在insert语句中维护一次,一次时保存Customer时,执行update更新LinkMan中外键一次,冗余了. 多余的维护关系语句,显然是客户这一端在维护关系。所以,我们要让一的一方放弃外键维护,由多的一方维护外键关系。在Customer对应的映射文件< set>中配置inverse属性。

		<!-- 
			inverse属性:配置关系是否维护
				false(默认值):Customer维护关系
				true:Customer放弃维护,全交给LinkMan维护
		 -->
		<set name="saleVisit" cascade="save-update" inverse="true">
			
			<key column="lkm_cust_id"></key>
		
			<one-to-many class="LinkMan"/>
		</set>

测试代码

public void name() {
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		
		Customer c1 = new Customer();
		c1.setCust_name("xx学院");
		
		LinkMan m1 = new LinkMan();
		m1.setLkm_name("吴老师");
		m1.setCustomer(c1);
		LinkMan m2 = new LinkMan();
		m2.setLkm_name("赵老师");
		m2.setCustomer(c1);
		
		c1.getLinkMens().add(m1);
		c1.getLinkMens().add(m2);
		
		session.save(c1);
		tx.commit();
		session.close();
	}

加入inverse属性之前生成的sql语句。
在这里插入图片描述
加入inverse之后生成的sql语句。减少了两次发送的update语句。
在这里插入图片描述

2.多对多关系

映射文件配置

此处以用户和角色为例,一个用户可以有多个角色,一个角色可以属于多个用户,这是典型的多对多关系,我们在用户映射文件中配置如下代码。

		<!-- 
		 	set标签
		 		name:关联的另一方属性名称
		 			private Set<Role> roles = new HashSet<Role>();
		 		table:中间表的表名
		  -->	
		<set name="roles" table="sys_user_role" cascade="save-update" >
			<!-- 
				key标签
					column:当前表中外键的名称
			 -->
			<key column="user_id" ></key>
			<!-- 
				many-to-many
					class:关联另一方类的全路径类名
					column:关联另一方表在中间表中的外键
			 -->
			<many-to-many class="Role" column="role_id" ></many-to-many>
		</set>

在Role对应的配置文件中添加如下代码。

		<!-- 
		 	set标签
		 		name:关联的另一方属性名称
		 			private Set<User> users = new HashSet<User>();
		 		table:中间表的表名
		  -->		
		<set name="users" table="sys_user_role" inverse="true" >
			<!-- 
				key标签
					column:当前表中外键的名称
			 -->
			<key column="role_id" ></key>
			<!-- 
				many-to-many
					class:关联另一方类的全路径类名
					column:关联另一方表在中间表中的外键
			 -->
			<many-to-many class="User" column="user_id" ></many-to-many>
		</set>

中间表
在这里插入图片描述
在多对多的保存操作中,如果进行了双向维护关系,就必须由一方放弃外键维护权,一般由被动方放弃,用户主动选择角色,角色就被动方,所以一般角色要放弃外键维护全。但是若只进行单向维护关系,那么就不要放弃外键维护权了。

二、Hibernate中的查询

1.OID检索方式

Customer customer = session.get(Customer.class, 1l);
Customer customer = session.load(Customer.class, 1l);

2.对象图导航检索

LinkMan linkMan = session.get(LinkMan.class,1l);
Customer customer = linkMan.getCustomer();

3.HQL检索

	//基本查询
	Query query = session.createQuery("from Customer");
	List<Customer> list = query.list();

	//排序查询
	Query query = session.createQuery("from Customer order by cust_id desc");
	List<Customer> list = query.list();

	//条件查询
		//按位置绑定参数
		Query query = session.createQuery("from Customer where cust_name=?");
		query.setParameter(0, "zhangsan");
		Customer customer = (Customer) query.uniqueResult();
		//按名称绑定参数
		Query query = session.createQuery("from Customer where cust_name=:name");
		query.setParameter("name", "zhangsan");
		Customer customer = (Customer) query.uniqueResult();
			
	//分页查询
	Query query = session.createQuery("from Customer");
	query.setFirstResult(5);
	query.setMaxResults(10);
	List<Customer> list = query.list();
	
	//统计查询
	Query query = session.createQuery("select count(*) from Customer");
	Long count = (Long) query.uniqueResult();
	
//投影查询
	//投影查询一列
	Query query = session.createQuery("select cust_name from Customer");
	List<String> list = query.list();
	//投影查询多列
	Query query = session.createQuery("select cust_id,cust_name from Customer");
	List<Object[]> list = query.list();
	//投影构造方式查询
	Query query = session.createQuery("select new Customer(cust_id,cust_name) from Customer");
	List<Customer> list = query.list();

4.QBC检索

	//简单查询
	Criteria criteria = session.createCriteria(Customer.class);
	List<Customer> list = criteria.list();

	//条件查询
	Criteria criteria = session.createCriteria(Customer.class);
	//criteria.add(Restrictions.eq("cust_name", "zhangsan"));
	criteria.add(Restrictions.like("cust_name","%zhang%"));
	List<Customer> list = criteria.list();

	//分页查询
	Criteria criteria = session.createCriteria(Customer.class);
	criteria.setFirstResult(5);
	criteria.setMaxResults(10);
	List<Customer> list = criteria.list();

	//排序查询
	Criteria criteria = session.createCriteria(Customer.class);
	criteria.addOrder(Order.desc("cust_id"));
	List<Customer> list = criteria.list();

	//排序查询
	Criteria criteria = session.createCriteria(Customer.class);
	criteria.setProjection(Projections.rowCount());
	Long count = (Long) criteria.uniqueResult();

	//离线查询
	//可将条件封装,从web层传递到service在传递到dao层
	DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
	dc.add(Restrictions.gt("cust_id",60L));//大于等于
	Criteria criteria = dc.getExecutableCriteria(session);
	List<Customer> list = criteria.list();

5.本地SQL检索

	//离线查询
	SQLQuery query = session.createSQLQuery("select cust_id,cust_name from tb_cst_customer");
	query.addEntity(Customer.class);
	List<Customer> list = query.list();

6.多表查询

//HQL多表查询
	//内连接
	List<Object[]> list = session.createQuery("from Customer c inner join c.linkMans").list();

	//迫切内连接
	List<Customer> list = session.createQuery("select distinct c from Customer c inner join fetch c.linkMens").list();

下图为普通内连接封装的list集合,很明显封装的结果为List<Object[]>,每一条数据都是封装两个对象的集合,从下图中可以看出集合中一个对象为Customer,customer对象中封装了一个LinkMan的set集合,集合中的另一个对象为LinkMan(linkMan被封装了两次)。
在这里插入图片描述
下图为迫切内连接封装的list集合,HQL语句中加入fetch后,会将属于客户的数据封装到Customer中,将数据联系人的数据封装到customer对象中的Set< LinkMan>集合中。迫切内连接查询结果会有重复数据,所以常加上关键字distinct。
在这里插入图片描述

三、查询优化

1.延迟加载

  • 类级延迟加载:是指查询某个对象时,是否采用有延迟,通常在< class>标签上配置lazy属性。
  • 关联级别延迟加载:是指查询一个对象关联的对象时,是否采用延迟加载,通常在< set>、< many-to-one>上配置lazy属性。
    hibernate类级延迟加载默认时延迟的,使用load方法可以看,在执行该方法时并不会发送sql语句,当使用到该方法加载的对象时才会执行查询获得真实对象。
Customer customer = session.load(Customer.class,1l);

关联级别延迟加载,< set>标签上通常有三种lazy属性取值。

  • true:默认值,采用延迟加载。

  • false:检索关联对象时,不采用延迟加载。

  • extra:及其懒惰。
    < many-to-one>标签上通常也是有三种取值。

  • proxy:默认值,取决于一的一方类上的lazy属性值。

  • false:检索关联对象时,不采用延迟加载。

  • no-proxy:不研究。

2.抓取策略

抓取策略指的是查询到某个对象的时候,如何抓取其关联的对象。在关联对象的标签上配置fetch属性。
< set>标签上通常有三个取值:

  • select:默认值,发送的是普通select语句查询。

  • join:发送的是一条迫切左外连接连接去查询。

  • subselect:发送的是一条子查询语句查询其关联的对象。
    < many-to-one>标签上的fetch有两个取值:

  • select:默认值,发送一条普通的select语句查询。

  • join:发送的是一条迫切左外连接连接去查询。
    lazy与fetch配置使用可以很好的提高性能,fetch若设为join,那么lazy就会失效
    在< set> 上fetch和lazy的组合效果。

//集合级别的关联
	//fetch:select 单表查询
	//lazy:true 使用时才加载集合数据.
	@Test
	public void fun1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//----------------------------------------------------
		
		Customer c = session.get(Customer.class, 2l);//发送一条select查询Customer
		
		Set<LinkMan> linkMens = c.getLinkMens();//关联级别
		
		System.out.println(linkMens);//发送一条select查询LinkMan
		
		//----------------------------------------------------
		tx.commit();
		session.close();
		
	}
	
	//集合级别的关联
		//fetch:select 单表查询
		//lazy:false 立即记载集合数据
		@Test
		public void fun2(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
			
			Customer c = session.get(Customer.class, 2l);//发送两条条select,一条查询Customer,一条查询LinkMan
			
			Set<LinkMan> linkMens = c.getLinkMens();//关联级别
			
			System.out.println(linkMens);
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}
		//集合级别的关联
		//fetch:select 单表查询
		//lazy:extra 极其懒惰.与懒加载效果基本一致. 如果只获得集合的size.只查询集合的size(count语句)
		@Test
		public void fun3(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
			
			Customer c = session.get(Customer.class, 2l);//发送一条select查询Customer
			
			Set<LinkMan> linkMens = c.getLinkMens();//关联级别
			
			System.out.println(linkMens.size());//发送一条select count(*) 统计语句
			
			System.out.println(linkMens); //发送一条select查询LinkMan
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}
		//集合级别的关联
		//fetch:join	多表查询
		//lazy:true|false|extra 失效.立即加载.
		@Test
		public void fun4(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
			
			Customer c = session.get(Customer.class, 2l); //发送一条迫切外连接直接将关联对象一起查询
			
			Set<LinkMan> linkMens = c.getLinkMens();//关联级别
			
			System.out.println(linkMens.size());
			
			System.out.println(linkMens);
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}
		
		@Test
		//fetch: subselect 子查询
		//lazy: true 懒加载
		public void fun5(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
				
			String  hql = "from Customer";
			//子查询不能查询某一个对象,查询多个对象来测试
			Query query = session.createQuery(hql);
			
			List<Customer> list = query.list(); //发送一条select查询Customer
			
			for(Customer c:list){
				System.out.println(c);
				System.out.println(c.getLinkMens().size());//发送一条select查询客户关联的LinkMan
				System.out.println(c.getLinkMens());
			}
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}
		@Test
		//fetch: subselect 子查询
		//lazy: false 立即加载
		public void fun6(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
				
			String  hql = "from Customer";
			
			Query query = session.createQuery(hql);
			
			List<Customer> list = query.list();//发送子查询查询Custome及其关联的LinkMan
			
			for(Customer c:list){
				System.out.println(c);
				System.out.println(c.getLinkMens().size());
				System.out.println(c.getLinkMens());
			}
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}
		@Test
		//fetch: subselect 子查询
		//lazy: extra 极其懒惰
		public void fun7(){
			Session session = HibernateUtils.openSession();
			Transaction tx = session.beginTransaction();
			//----------------------------------------------------
				
			String  hql = "from Customer";
			
			Query query = session.createQuery(hql);
			
			List<Customer> list = query.list();
			
			for(Customer c:list){
				System.out.println(c);
				System.out.println(c.getLinkMens().size());
				System.out.println(c.getLinkMens());
			}
			
			//----------------------------------------------------
			tx.commit();
			session.close();
			
		}

在< many-to-one>上的组合效果

	@Test
	//fetch:select	单表查询
	//lazy:proxy  
		//customer-true 懒加载
	public void fun1(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//----------------------------------------------------
		
		LinkMan lm = session.get(LinkMan.class, 3l);//发送一条select查询LinkMan
		
		Customer customer = lm.getCustomer();
		
		System.out.println(customer);//发送一条select查询Customer
		
		//----------------------------------------------------
		tx.commit();
		session.close();
		
	}
	@Test
	//fetch:join	多表
	//lazy: 失效  
	public void fun3(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//----------------------------------------------------
		
		LinkMan lm = session.get(LinkMan.class, 3l);//发送一条迫切外连接直接将关联对象一起查询
		
		Customer customer = lm.getCustomer();
		
		System.out.println(customer);
		
		//----------------------------------------------------
		tx.commit();
		session.close();
		
	}
	@Test
	//fetch:select	单表查询
	//lazy:proxy  
		//customer-false 立即加载
	public void fun2(){
		Session session = HibernateUtils.openSession();
		Transaction tx = session.beginTransaction();
		//----------------------------------------------------
		
		LinkMan lm = session.get(LinkMan.class, 3l);//发送两条条select,一条查询LinkMan,一条查询Customer
		
		Customer customer = lm.getCustomer();
		
		System.out.println(customer);
		
		//----------------------------------------------------
		tx.commit();
		session.close();
		
	}

3.批量抓取

批量抓取是指一次抓取关联对象的个数,通常在< set>上配置batch-size属性,如:batch-size=“4”,那么就一次抓取该对象的四个关联对象。还可以在< class>上配置。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值