hibernate第三天——session的缓存与事务隔离级别,一对一关系,多种方式查询

1、session的缓存与事务隔离级别

(1)、查询数据(session的缓存):
先在session的缓存中找,如果找不到再找数据库。这样虽然提高性能,但是存在一定的风险,可能另一个线程改变了数据库内容,但是查询的还是缓存中的数据。
class Session{
	private Map<Serializable, Object> cache; // 缓存

	public Object get(.., id){
		Object obj = cache.get(id);
		if(obj == null){
			obj = "select * from xxx whereid=?";
			cache.put(id, obj);
		}
		return obj;
	}
}

事务隔离级别
数字类型的常量值。
session.refresh()方法。
清除缓存,进行重新查询。


在Hibernate中指定事务隔离级别。
(2)、事务与事务隔离级别:

读未提交(read uncommitted):改了还没提交就获得了新的数据,几乎不使用。
读已提交(read commited):改了提交了才能重新获得。用的比较广泛
可重复读(repeatable read):事务开始时创建快照,不关注其他事务,其他事物不改变状态。。默认的事务隔离
串行化(不可并发):只能一个一个的来。对数据的要求最为严格,自然也是性能最差的一种隔离级别。


hibernate的配置文件:
<property name="connection.isolation">2</property>

2、一对一映射关系

电话,身份证号,都是String类型

集合可以初始化,但是对象不要初始化



基于外键的可以解除关系。

(1)、基于外键的方式:
IdCard.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.i_hbm_oneToOne">
	
	<class name="IdCard" table="idCard">
		<id name="id">
        	<generator class="native"></generator>
		</id>
		<property name="number"/>
		
		<!-- person属性,Person类型。
			表达的是本类与Person的一对一。
			采用基于外键的一对一映射方式,本方有外键方。 -->
		<many-to-one name="person" class="Person" column="personId" unique="true"></many-to-one>
		
	</class>
	
</hibernate-mapping>


Person.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.i_hbm_oneToOne">
	
	<class name="Person" table="person">
		<id name="id">
        	<generator class="native"></generator>
		</id>
		<property name="name"/>
		
		<!-- idCard属性,IdCard类型。
			表达的是本类与IdCard的一对一。
			采用基于外键的一对一映射方式,本方无外键方。
			property-ref属性:
				写的是对方映射中外键列对应的属性名。	
		 -->
		<one-to-one name="idCard" class="IdCard" property-ref="person"/>
		
	</class>
	
</hibernate-mapping>

测试App:
package cn.itcast.i_hbm_oneToOne;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Person.class)// 添加Hibernate实体类(加载对应的映射文件)
			.addClass(IdCard.class)// 添加Hibernate实体类(加载对应的映射文件)
			.buildSessionFactory();

	// 保存,有关联关系
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 新建对象
		Person person = new Person();
		person.setName("张三");

		IdCard idCard = new IdCard();
		idCard.setNumber("100000011X");

		// 关联起来
		// person.setIdCard(idCard);
		idCard.setPerson(person);

		// 保存
		session.save(person);
		session.save(idCard);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 获取,可以获取到关联的对方
	@Test
	public void testGet() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 获取一方,并显示另一方信息
		// Person person = (Person) session.get(Person.class, 1);
		// System.out.println(person);
		// System.out.println(person.getIdCard());

		IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		System.out.println(idCard);
		System.out.println(idCard.getPerson());

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();

	}

	// 解除关联关系:一对一中,只能有外键方可以维护关联关系。
	@Test
	public void testRemoveRelation() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 从有外键方解除关系,可以。
		// IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		// idCard.setPerson(null);

		// 从无外键方解除关系,不可以。
		Person person = (Person) session.get(Person.class, 1);
		person.setIdCard(null);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 删除对象,对关联对象的影响
	@Test
	public void testDelete() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// a, 如果没有关联的对方:能删除。
		// b, 如果有关联的对方且可以维护关联关系(有外键方),他就会先删除关联关系,再删除自己。
		// c, 如果有关联的对方且不能维护关联关系(无外键方),所以会直接执行删除自己,就会有异常。

		IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		session.delete(idCard);

		// Person person = (Person) session.get(Person.class, 1);
		// session.delete(person);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

小结:
有外键方的可以自动维护表关系。
inverse属性只用于一对多。
外键都是many-one。
一对一的有外键的方式只能从有外键的一方来维护表结构。

单向关联:
        单向一对多。
        单向多对一。
        单向多对多。
        单向一对一(只能做从有外键方到无外键方的单向关联)

(2)、基于主键的方式:
IdCard.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.i_hbm_oneToOne2">
	
	<class name="IdCard" table="idCard2">
		<id name="id">
			<!-- 当使用基于主键的一对一映射时,
				有外键方的主键生成策略一定要是foreign。
				参数property:
					生成主键值时所根据的对象。
			 -->
        	<generator class="foreign">
        		<param name="property">person</param>
        	</generator>
		</id>
		<property name="number"/>
		
		<!-- person属性,Person类型。
			表达的是本类与Person的一对一。
			采用基于主键的一对一映射方式,本方有外键方。 -->
		<one-to-one name="person" class="Person" constrained="true"></one-to-one>
		
	</class>
	
</hibernate-mapping>


Person.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.i_hbm_oneToOne2">
	
	<class name="Person" table="person2">
		<id name="id">
        	<generator class="native"></generator>
		</id>
		<property name="name"/>
		
		<!-- idCard属性,IdCard类型。
			表达的是本类与IdCard的一对一。
			采用基于主键的一对一映射方式,本方无外键方。
		 -->
		<one-to-one name="idCard" class="IdCard"></one-to-one>
		
		
	</class>
	
</hibernate-mapping>

测试App:

package cn.itcast.i_hbm_oneToOne2;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Person.class)// 添加Hibernate实体类(加载对应的映射文件)
			.addClass(IdCard.class)// 添加Hibernate实体类(加载对应的映射文件)
			.buildSessionFactory();

	// 保存,有关联关系
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 新建对象
		Person person = new Person();
		person.setName("张三");

		IdCard idCard = new IdCard();
		idCard.setNumber("100000011X");

		// 关联起来
		person.setIdCard(idCard);
		idCard.setPerson(person);

		// 保存
		session.save(person);
		session.save(idCard);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 获取,可以获取到关联的对方
	@Test
	public void testGet() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 获取一方,并显示另一方信息
		// Person person = (Person) session.get(Person.class, 1);
		// System.out.println(person);
		// System.out.println(person.getIdCard());

		IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		System.out.println(idCard);
		System.out.println(idCard.getPerson());

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();

	}

	// 解除关联关系:使用基于主键的一对一映射方式:双方都不可以解除关联关系。
	@Test
	public void testRemoveRelation() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 基于主键的一对一映射:从有外键方解除关系,不可以,因为主键 不能为null。
		IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		idCard.setPerson(null);

		// // 基于主键的一对一映射:从无外键方解除关系,不可以。
		// Person person = (Person) session.get(Person.class, 1);
		// person.setIdCard(null);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 删除对象,对关联对象的影响
	@Test
	public void testDelete() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// a, 如果没有关联的对方:能删除。
		// c, 如果有关联的对方:因为会直接执行删除自己,所以无外键方会有异常,有外键方没有异常。

		IdCard idCard = (IdCard) session.get(IdCard.class, 1);
		session.delete(idCard);

		// Person person = (Person) session.get(Person.class, 1);
		// session.delete(person);

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

3、继承结构


(1)、使用1张表
Article.cfg.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.j_hbm_extends">
	
	<!-- 
		discriminator-value属性:
			用于鉴别是哪个类的一个值,表示这个值就是这个类。
			如果不写,默认为类的全限定名。
	 -->
	<class name="Article" table="article" discriminator-value="Aticle">
		<id name="id">
        	<generator class="native"/>
		</id>
		
		<!-- 用于鉴别是什么类型的一个列 -->
		<discriminator type="string" column="class_"></discriminator>
		
		<property name="title"/>
		<property name="content" type="text" length="10000"/>
		<property name="postTime" type="timestamp"/>
		
		
		<!-- 子类:Topic -->
		<subclass name="Topic" discriminator-value="Topic">
			<property name="type"></property>
		</subclass>
		
		
		<!-- 子类:Reply -->
		<subclass name="Reply" discriminator-value="Reply">
			<property name="floor"></property>
		</subclass>
		
	</class>
	
</hibernate-mapping>

(2)、每个类一张表,抽象类也对应表
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.j_hbm_extends2">
	
	<!-- 采用每个类一张表的方式,抽象类也对应表。 -->
	<class name="Article" table="article2">
		<id name="id">
        	<generator class="native"/>
		</id>
		<property name="title"/>
		<property name="content" type="text" length="10000"/>
		<property name="postTime" type="timestamp"/>
		
		
		<!-- 子类:Topic -->
		<joined-subclass name="Topic" table="topic2">
			<key column="id"></key>
			<property name="type"></property>
		</joined-subclass>
		
		
		<!-- 子类:Reply -->
		<joined-subclass name="Reply" table="reply2">
			<key column="id"></key>
			<property name="floor"></property>
		</joined-subclass>
		
	</class>
	
</hibernate-mapping>

(3)、每个类一张表,抽象类不对应表
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="cn.itcast.j_hbm_extends3">
	
	<!-- 采用每个具体类一张表的方式,抽象类不对应表。
		abstract默认为false,设为true表示本类不对应表(类可以不是abstract的),这时就会忽略table属性。
	 -->
	<class name="Article" abstract="true" table="article3">
		<id name="id">
			<!-- 
				当使用每个具体类一张表的方式时,主键生成策略不能是identity。
				因为在整个继承结构中,主键值是不能重复的。
			 -->
        	<generator class="hilo">
        		<param name="table">hi_value</param>
                <param name="column">next_value</param>
                <param name="max_lo">100</param>
        	</generator>
		</id>
		<property name="title"/>
		<property name="content" type="text" length="10000"/>
		<property name="postTime" type="timestamp"/>
		
		
		<!-- 子类:Topic -->
		<union-subclass name="Topic" table="topic3">
			<property name="type"></property>
		</union-subclass>
		
		
		<!-- 子类:Reply -->
		<union-subclass name="Reply" table="reply3">
			<property name="floor"></property>
		</union-subclass>
		
	</class>
	
</hibernate-mapping>


<!-- table: table name (default <tt>hibernate_sequences</tt>)
primary_key_column: key column name (default <tt>sequence_name</tt>)
value_column: hi value column name(default <tt>sequence_next_hi_value</tt>)
primary_key_value: key value for the current entity (default to the entity's primary table name)
primary_key_length: length of the key column in DB represented as a varchar (default to 255)
max_lo: max low value before increasing hi (default to Short.MAX_VALUE)
-->
<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
<param name="table">hi_value</param>
<param name="max_lo">100</param>
</generator>


4、多种查询方式——hql

1,简单的查询
2,带上过滤条件的(可以使用别名):Where
3,带上排序条件的:Order By
4,指定select子句(不可以使用select *)
可以使用new语法,指定把查询出的部分属性封装到对象中
5,执行查询,获得结果(list、uniqueResult、分页 )
6,方法链


1,聚集函数
2,分组
3,连接查询 / HQL是面向对象的查询
4,查询时使用参数
方式一:使用'?'占位
方式二:使用变量名
5,使用命名查询
6,update与delete,不会通知Session缓存
在update或delete后,需要refresh(obj)一下以获取最新的状态



<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!-- 
	auto-import表示在HQL中写类的简单名称时,是否自动导入当前这个包。
	即为true时,在HQL中可以写简单名称,表示当前这个类。
	当为false时,在HQL中就得写全限定名了。
	默认为true。
 -->
<hibernate-mapping package="cn.itcast.k_query_hql" auto-import="true">
	
	<class name="Employee" table="employee">
		<id name="id">
        	<generator class="native"></generator>
		</id>
		<property name="name" type="string" column="name"/>
		
		<!-- department属性,表达的是本类与Department的多对一 -->
		<many-to-one name="department" class="Department" column="departmentId"></many-to-one>
		
	</class>
	
	<!-- 定义命名的查询 -->
	<query name="queryByIdRange">
		<![CDATA[FROM Employee e WHERE e.id >= :idMin AND e.id <= :idMax]]>
	</query>
	
</hibernate-mapping>

1,简单的查询
hql = "FROM Employee";
hql = "FROM Employee AS e"; // 使用别名
hql = "FROM Employee e"; // 使用别名,as关键字可省略。别名用来防止关键字冲突,推荐使用别名


2,带上过滤条件的(可以使用别名):Where
hql = "FROM Employee WHERE id<10";
hql = "FROM Employee e WHERE e.id<10";
hql = "FROM Employee e WHERE e.id<10 AND e.id>5";


3,带上排序条件的:Order By
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name";
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC";
hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";


4,指定select子句(不可以使用select *)
hql = "SELECT e FROM Employee e"; // 相当于"FROM Employee e"
hql = "SELECT e.name FROM Employee e"; // 只查询一个列,返回的集合的元素类型就是这个属性的类型
hql = "SELECT e.id,e.name FROM Employee e"; // 查询多个列,返回的集合的元素类型是Object数组
hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; // 可以使用new语法,指定把查询出的部分属性封装到对象中


5,执行查询,获得结果(list、uniqueResult、分页 )
Query query = session.createQuery("FROM Employee e WHERE id<3");
query.setFirstResult(0);
query.setMaxResults(10);
// List list = query.list(); // 查询的结果是一个List集合
Employee employee = (Employee) query.uniqueResult();// 查询的结果是唯一的一个结果,当结果有多个,就会抛异常
System.out.println(employee);


1,聚集函数:count(), max(), min(), avg(), sum()
hql = "SELECT COUNT(*) FROM Employee"; // 返回的结果是Long型的
hql = "SELECT min(id) FROM Employee"; // 返回的结果是id属性的类型
Number result = (Number) session.createQuery(hql).uniqueResult();
System.out.println(result.getClass());
System.out.println(result);


2,分组: Group By ... Having
hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name";
hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name HAVING count(e.id)>1";
hql = "SELECT e.name,COUNT(e.id) FROM Employee e WHERE id<9 GROUP BY e.name HAVING count(e.id)>1";
---
hql = "SELECT e.name,COUNT(e.id) " + //
"FROM Employee e " + //
"WHERE id<9 " + //
// "GROUP BY e.name " + //
// "HAVING count(e.id)>1 " + //
"ORDER BY count(e.id) ASC";
---
hql = "SELECT e.name,COUNT(e.id) AS c " + //
"FROM Employee e " + //
"WHERE id<9 " + //
// "GROUP BY e.name " + //
// "HAVING count(e.id)>1 " + // 在having子句中不能使用列别名
"ORDER BY c ASC"; // 在orderby子句中可以使用列别名


3,连接查询 / HQL是面向对象的查询
>> 内连接(inner关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Employee e JOIN e.department d";
hql = "SELECT e.id,e.name,d.name FROM Employee e INNER JOIN e.department d";
>> 左外连接(outer关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Employee e LEFT OUTER JOIN e.department d";
>> 右外连接(outer关键字可以省略)
hql = "SELECT e.id,e.name,d.name FROM Employee e RIGHT JOIN e.department d";
可以使用更方便的方法
hql = "SELECT e.id,e.name,e.department.name FROM Employee e";


4,查询时使用参数
>> 方式一:使用'?'占位
hql = "FROM Employee e WHERE id BETWEEN ? AND ?";
List list = session.createQuery(hql)//
.setParameter(0, 5)// 设置参数,第1个参数的索引为0。
.setParameter(1, 15)//
.list();


>> 方式二:使用变量名
hql = "FROM Employee e WHERE id BETWEEN :idMin AND :idMax";
List list = session.createQuery(hql)//
.setParameter("idMax", 15)//
.setParameter("idMin", 5)//
.list();


当参数是集合时,一定要使用setParameterList()设置参数值
hql = "FROM Employee e WHERE id IN (:ids)";
List list = session.createQuery(hql)//
.setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })//
.list();


5,使用命名查询
Query query = session.getNamedQuery("queryByIdRange");
query.setParameter("idMin", 3);
query.setParameter("idMax", 10);
List list = query.list();


6,update与delete,不会通知Session缓存
>> Update
int result = session.createQuery(//
"UPDATE Employee e SET e.name=? WHERE id>15")//
.setParameter(0, "无名氏")//
.executeUpdate(); // 返回int型的结果,表示影响了多少行。
System.out.println("result = " + result);
>> Delete

Employee.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<!-- 
	auto-import表示在HQL中写类的简单名称时,是否自动导入当前这个包。
	即为true时,在HQL中可以写简单名称,表示当前这个类。
	当为false时,在HQL中就得写全限定名了。
	默认为true。
 -->
<hibernate-mapping package="cn.itcast.k_query_hql" auto-import="true">
	
	<class name="Employee" table="employee">
		<id name="id">
        	<generator class="native"></generator>
		</id>
		<property name="name" type="string" column="name"/>
		
		<!-- department属性,表达的是本类与Department的多对一 -->
		<many-to-one name="department" class="Department" column="departmentId"></many-to-one>
		
	</class>
	
	<!-- 定义命名的查询 -->
	<query name="queryByIdRange">
		<![CDATA[FROM Employee e WHERE e.id >= :idMin AND e.id <= :idMax]]>
	</query>
	
</hibernate-mapping>


App:
package cn.itcast.k_query_hql;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Department.class)// 添加Hibernate实体类(加载对应的映射文件)
			.addClass(Employee.class)// 添加Hibernate实体类(加载对应的映射文件)
			.buildSessionFactory();

	// 准备数据
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 保存一些部门数据
		for (int i = 1; i <= 10; i++) {
			Department department = new Department();
			department.setName("开发部_" + i);
			session.save(department);
		}

		// 保存一些员工数据
		for (int i = 1; i <= 20; i++) {
			Employee employee = new Employee();
			employee.setName("李XX_" + i);
			session.save(employee);
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 使用HQL查询
	// HQL: Hibernate Query Language.
	// 特点:
	// >> 1,与SQL相似,SQL中的语法基本上都可以直接使用。
	// >> 2,SQL查询的是表和表中的列;HQL查询的是对象与对象中的属性。
	// >> 3,HQL的关键字不区分大小写,类名与属性名是区分大小写的。
	// >> 4,SELECT可以省略.
	@Test
	public void testHql() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------
		String hql = null;

		// 1,简单的查询
		// hql = "FROM Employee";
		// hql = "FROM Employee AS e"; // 使用别名
		// hql = "FROM Employee e"; // 使用别名,as关键字可省略。别名用来防止关键字冲突,推荐使用别名

		// 2,带上过滤条件的(可以使用别名):Where
		// hql = "FROM Employee WHERE id<10";
		// hql = "FROM Employee e WHERE e.id<10";
		// hql = "FROM Employee e WHERE e.id<10 AND e.id>5";

		// 3,带上排序条件的:Order By
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name";
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC";
		// hql = "FROM Employee e WHERE e.id<10 ORDER BY e.name DESC, id ASC";

		// 4,指定select子句(不可以使用select *)
		// hql = "SELECT e FROM Employee e"; // 相当于"FROM Employee e"
		// hql = "SELECT e.name FROM Employee e"; // 只查询一个列,返回的集合的元素类型就是这个属性的类型
		// hql = "SELECT e.id,e.name FROM Employee e"; // 查询多个列,返回的集合的元素类型是Object数组
		// hql = "SELECT new Employee(e.id,e.name) FROM Employee e"; // 可以使用new语法,指定把查询出的部分属性封装到对象中

		// 5,执行查询,获得结果(list、uniqueResult、分页 )
		// Query query = session.createQuery("FROM Employee e WHERE id<3");
		// query.setFirstResult(0);
		// query.setMaxResults(10);
		// // List list = query.list(); // 查询的结果是一个List集合
		// Employee employee = (Employee) query.uniqueResult();// 查询的结果是唯一的一个结果,当结果有多个,就会抛异常
		// System.out.println(employee);

		// 6,方法链
		List list = session.createQuery(//
				"FROM Employee")//
				.setFirstResult(0)//
				.setMaxResults(10)//
				.list();

		// // ----- 执行查询
		// List list = session.createQuery(hql).list();
		//
		// ----- 显示结果
		for (Object obj : list) {
			if (obj.getClass().isArray()) {
				System.out.println(Arrays.toString((Object[]) obj));
			} else {
				System.out.println(obj);
			}
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void testHql_2() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------
		String hql = null;

		// 1,聚集函数:count(), max(), min(), avg(), sum()
		// hql = "SELECT COUNT(*) FROM Employee"; // 返回的结果是Long型的
		// hql = "SELECT min(id) FROM Employee"; // 返回的结果是id属性的类型
		// Number result = (Number) session.createQuery(hql).uniqueResult();
		// System.out.println(result.getClass());
		// System.out.println(result);

		// 2,分组: Group By ... Having
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name";
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e GROUP BY e.name HAVING count(e.id)>1";
		// hql = "SELECT e.name,COUNT(e.id) FROM Employee e WHERE id<9 GROUP BY e.name HAVING count(e.id)>1";
		// ---
		// hql = "SELECT e.name,COUNT(e.id) " + //
		// "FROM Employee e " + //
		// "WHERE id<9 " + //
		// "GROUP BY e.name " + //
		// "HAVING count(e.id)>1 " + //
		// "ORDER BY count(e.id) ASC";
		// ---
		// hql = "SELECT e.name,COUNT(e.id) AS c " + //
		// "FROM Employee e " + //
		// "WHERE id<9 " + //
		// "GROUP BY e.name " + //
		// "HAVING count(e.id)>1 " + // 在having子句中不能使用列别名
		// "ORDER BY c ASC"; // 在orderby子句中可以使用列别名

		// 3,连接查询 / HQL是面向对象的查询
		// >> 内连接(inner关键字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e JOIN e.department d";
		// hql = "SELECT e.id,e.name,d.name FROM Employee e INNER JOIN e.department d";
		// >> 左外连接(outer关键字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e LEFT OUTER JOIN e.department d";
		// >> 右外连接(outer关键字可以省略)
		// hql = "SELECT e.id,e.name,d.name FROM Employee e RIGHT JOIN e.department d";
		// 可以使用更方便的方法
		// hql = "SELECT e.id,e.name,e.department.name FROM Employee e";

		// 4,查询时使用参数
		// >> 方式一:使用'?'占位
		// hql = "FROM Employee e WHERE id BETWEEN ? AND ?";
		// List list = session.createQuery(hql)//
		// .setParameter(0, 5)// 设置参数,第1个参数的索引为0。
		// .setParameter(1, 15)//
		// .list();

		// >> 方式二:使用变量名
		// hql = "FROM Employee e WHERE id BETWEEN :idMin AND :idMax";
		// List list = session.createQuery(hql)//
		// .setParameter("idMax", 15)//
		// .setParameter("idMin", 5)//
		// .list();

		// 当参数是集合时,一定要使用setParameterList()设置参数值
		// hql = "FROM Employee e WHERE id IN (:ids)";
		// List list = session.createQuery(hql)//
		// .setParameterList("ids", new Object[] { 1, 2, 3, 5, 8, 100 })//
		// .list();

		// 5,使用命名查询
		// Query query = session.getNamedQuery("queryByIdRange");
		// query.setParameter("idMin", 3);
		// query.setParameter("idMax", 10);
		// List list = query.list();

		// 6,update与delete,不会通知Session缓存
		// >> Update
		// int result = session.createQuery(//
		// "UPDATE Employee e SET e.name=? WHERE id>15")//
		// .setParameter(0, "无名氏")//
		// .executeUpdate(); // 返回int型的结果,表示影响了多少行。
		// System.out.println("result = " + result);
		// >> Delete
		int result = session.createQuery(//
				"DELETE FROM Employee e WHERE id>15")//
				.executeUpdate(); // 返回int型的结果,表示影响了多少行。
		System.out.println("result = " + result);

		// ----- 执行查询并显示结果
		// // List list = session.createQuery(hql).list();
		// for (Object obj : list) {
		// if (obj.getClass().isArray()) {
		// System.out.println(Arrays.toString((Object[]) obj));
		// } else {
		// System.out.println(obj);
		// }
		// }

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	@Test
	public void testHql_DML() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 第一次显示名称
		Employee employee = (Employee) session.get(Employee.class, 13);
		System.out.println(employee.getName());

		// update与delete,不会通知Session缓存
		int result = session.createQuery(//
				"UPDATE Employee e SET e.name=? WHERE id>10")//
				.setParameter(0, "无名氏3")//
				.executeUpdate(); // 返回int型的结果,表示影响了多少行。

		// 第二次显示名称
		// 在update或delete后,需要refresh(obj)一下以获取最新的状态
		session.refresh(employee);
		System.out.println(employee.getName());

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

5、多种查询方式——qbc

package cn.itcast.k_query_qbc;

import java.util.Arrays;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.junit.Test;

public class App {

	private static SessionFactory sessionFactory = new Configuration()//
			.configure()//
			.addClass(Department.class)// 添加Hibernate实体类(加载对应的映射文件)
			.addClass(Employee.class)// 添加Hibernate实体类(加载对应的映射文件)
			.buildSessionFactory();

	// 准备数据
	@Test
	public void testSave() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 保存一些部门数据
		for (int i = 1; i <= 10; i++) {
			Department department = new Department();
			department.setName("开发部_" + i);
			session.save(department);
		}

		// 保存一些员工数据
		for (int i = 1; i <= 20; i++) {
			Employee employee = new Employee();
			employee.setName("李XX_" + i);
			session.save(employee);
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

	// 使用QBC方式查询:Query By Criteria
	@Test
	public void testQBC() throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		// --------------------------------------------

		// 创建Criteria对象
		Criteria criteria = session.createCriteria(Employee.class);
		// 增加过滤条件
		criteria.add(Restrictions.ge("id", 1));
		criteria.add(Restrictions.le("id", 5));
		// 增加排序条件
		criteria.addOrder(Order.desc("name"));
		criteria.addOrder(Order.desc("id"));
		// 执行查询
		// criteria.setFirstResult(0);
		// criteria.setMaxResults(100);
		// criteria.uniqueResult();
		// criteria.list()
		List list = criteria.list();
		// 显示结果
		for (Object obj : list) {
			if (obj.getClass().isArray()) {
				System.out.println(Arrays.toString((Object[]) obj));
			} else {
				System.out.println(obj);
			}
		}

		// --------------------------------------------
		session.getTransaction().commit();
		session.close();
	}

}

一、一对一的关联关系映射(外键 + 唯一)
       基于外键的
                有外键方:<many-to-one name="obj" class=".." column=".." unique="true"/>
                无外键方:<one-to-one name=".." class=".." property-ref="obj"/>

        基于主键的
                有外键方:<one-to-one ...>
                无外键方:<one-to-one ...>

        操作:
                在采用基于外键的方式时:只有有外键方可以维护关联关系。
                在采用基于主键的方式时:双方都不可以维护关系。

二、继承结构映射
        1,整个继承结构使用一张表。列上不能有not-null="true"。
        2,每个类对应一张表,抽象类也对应表。
        3,每个具体类对应一张表,抽象类不对应表。

三、HQL语句
        与SQL的语法类似。
        HQL查询的对象、属性,所以写的时候写的是类名、属性名。
        HQL的关键字不区分大小写,类名与属性名区分大小写。
        语法:
                SELECT           别名/属性名/表达式
                FROM              实体 AS 别名
                WHERE           过滤条件
                ORDER BY      排序条件

                SELECT           别名/属性名/表达式
                FROM              实体 AS 别名
                WHERE           过滤条件
                GROUP BY     分组条件
                HAVING          分组后的结果的过滤条件
                ORDER BY     排序条件 




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值