1、值类型的集合
集合元素是普通类型
(1)、数据存放类型
Set
HashSet 无序,不重复
List
有序,可重复
HashSet 无序,不重复
List
有序,可重复
Map
键值对
HashMap 无序,不重复(以key为准)
-----------------------------------------------
数组
Bag
无序,可重复
List
键值对
HashMap 无序,不重复(以key为准)
-----------------------------------------------
数组
Bag
无序,可重复
List
集合映射的表结构学习路线图:
(2)、映射集合属性——set
Set
HashSet 无序,不重复
HashSet 无序,不重复
User实体:
private Integer id;
private String name;
private Set<String> addressSet = new HashSet<String>();
<?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.e_hbm_collection">
<class name="User" table="user">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"/>
<!-- addressSet属性,Set集合
table属性:集合表的名称
key子元素:集合外键的列名
element子元素:存放集合元素的列的信息
sort属性:"unsorted|natural|comparatorClass"
默认为:unsorted
order-by属性:写的是order by 子句,是SQL语句,是操作的集合表。
这是在查询数据时指定orderby子句。
-->
<set name="addressSet" table="user_addressSet" order-by="address ASC">
<key column="userId"></key>
<element type="string" column="address"></element>
</set>
</class>
</hibernate-mapping>
测试app:
private static SessionFactory sessionFactory;
//初始化工厂
static {
Configuration configuration = new Configuration();
//读取指定的配置文件
configuration.configure();
//configuration.buildSessionFactory();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
@Test
public void testSave(){
User user = new User();
user.setName("张三");
user.getAddressSet().add("江苏省");
user.getAddressSet().add("江苏省");
user.getAddressSet().add("南京市");
//获取session
Session session = sessionFactory.openSession();
//开启事务
Transaction tx =session.beginTransaction();
session.save(user);
//提交事务
tx.commit();
//关闭session,释放资源
session.close();
}
由于set是不重复的,所以只会存在一个“江苏省”
(3)、映射集合属性——list
List有序,可重复
User.hbm.xml:
<!-- addressList属性,List集合
list-index:用于存放索引的列
-->
<list name="addressList" table="user_addressList">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="address"></element>
</list>
user.getAddressList().add("江苏省");
user.getAddressList().add("南京市");
user.getAddressList().add("南京市");
由于list是允许重复的,因此会有两个”南京市“
(4)、映射集合属性——数组
User.hbm.xml:<!-- addressArray属性,数组。与List的映射基本一致 -->
<array name="addressArray" table="user_addressArray">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="address"></element>
</array>
测试app:
// >> 数组
user.setAddressArray(new String[] { "御富科贸园", "棠东东路" });
System.out.println(Arrays.toString(user.getAddressArray()));
(5)、映射集合属性——MAP
User.hbm.xml:
<!-- addressMap属性,Map集合 -->
<map name="addressMap" table="user_addressMap">
<key column="userId"></key>
<map-key type="string" column="key_"></map-key>
<element type="string" column="address"></element>
</map>
测试app:
// >> Map集合
user.getAddressMap().put("公司", "御富科贸园");
user.getAddressMap().put("家庭", "棠东东路");
(6)、映射集合属性——BAG
Bag无序,可重复
List
private List<String> addressBag = new ArrayList<String>();
User.hbm.xml:
<!-- addressBag属性,Bag集合:无序,可重复。与Set集合的映射基本一致 -->
<bag name="addressBag" table="user_addressBag">
<key column="userId"></key>
<element type="string" column="address"></element>
</bag>
测试app:
// >> Bag集合
user.getAddressBag().add("御富科贸园");
user.getAddressBag().add("棠东东路");
user.getAddressBag().add("棠东东路");
使用集合属性时,一定要使用接口,而不能声明为具体的实现类。
因为经过Session操作后,集合就变成了Hibernate自己的集合实现类。
(7)、sort属性——set、map(效率低,不常用)
使用sort属性要使用有序set,TreeSet。
测试app:
sort属性:"unsorted|natural|comparatorClass"
默认为:unsorted
默认为:unsorted
内存排序
<set name="addressSet" table="two_user_addressSet" sort="natural">
<key column="userID"></key>
<element type="string" column="address"></element>
</set>
测试app:
User user = new User();
user.setName("张三");
user.setAddressSet(new TreeSet<String>());
user.getAddressSet().add("3江苏省");
user.getAddressSet().add("3江苏省");
user.getAddressSet().add("1南京市");
(8)、order-by属性
order-by属性:写的是order by 子句,是SQL语句,是操作的集合表。DESC降序,ASC升序。
这是在查询数据时指定orderby子句。
这是在查询数据时指定orderby子句。
测试app:
User.hbm.xml:
User.hbm.xml:
<set name="addressSet" table="two_user_addressSet" order-by="address DESC">
<key column="userID"></key>
<element type="string" column="address"></element>
</set>
2、实体类型的集合与关联关系
集合元素是另一个实体
(1)、一对多关联关系
只需要两张表
对于一对多的关系,需要考虑的操作:
- 保存,有关联关系
- 获取,可以获取到关联的对方
- 解除关联关系
- 删除对象,对关联对象的影响
没有外键的可以放弃维护,有外键的必须维护。被依赖的要先保存,不被依赖的后保存。
Department.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="seu.xinci.relationship.one_many.pojo">
<class name="Department" table="one_many_department">
<!-- 主键-->
<id name="id" type="integer" column="id">
<!--自动增长-->
<generator class="native" />
</id>
<!-- 一般 -->
<property name="name" type="string" column="name" />
<!-- employees属性,Set集合,表达的是本类与Employee的一对多
class属性:关联的实体类型
key子元素:对方表中的外键列(多方的那个表)
inverse属性:
默认为false,表示本方维护关联关系。
如果为true,表示本方不维护关联关系。
只是影响是否能设置外键列的值(设成有效值或是null值),对获取信息没有影响。-->
<set name="employees" inverse="true">
<key column="departmentId"></key>
<one-to-many class="seu.xinci.relationship.one_many.pojo.Employee"></one-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="seu.xinci.relationship.one_many.pojo">
<class name="Employee" table="one_many_employee">
<!-- 主键-->
<id name="id" type="integer" column="id">
<!--自动增长-->
<generator class="native" />
</id>
<!-- 一般 -->
<property name="name" type="string" column="name" />
<many-to-one name="department" class="Department" column="departmentId"></many-to-one>
</class>
</hibernate-mapping>
测试App:
package cn.itcast.f_hbm_oneToMany;
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();
// --------------------------------------------
// 新建对象
Department department = new Department();
department.setName("开发部");
Employee employee1 = new Employee();
employee1.setName("张三");
Employee employee2 = new Employee();
employee2.setName("李四");
// 关联起来
employee1.setDepartment(department);
employee2.setDepartment(department);
department.getEmployees().add(employee1);
department.getEmployees().add(employee2);
// 保存
// session.save(employee1);
// session.save(employee2);
session.save(department); // 保存部门
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 获取,可以获取到关联的对方
@Test
public void testGet() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// 获取一方,并显示另一方信息
Department department = (Department) session.get(Department.class, 1);
System.out.println(department);
System.out.println(department.getEmployees());
// Employee employee = (Employee) session.get(Employee.class, 1);
// System.out.println(employee);
// System.out.println(employee.getDepartment());
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 解除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// // 从员工方解除
// Employee employee = (Employee) session.get(Employee.class, 1);
// employee.setDepartment(null);
// 从部门方解除(与inverse有关系,为false时可以解除)
Department department = (Department) session.get(Department.class, 1);
department.getEmployees().clear();
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除对象,对关联对象的影响
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// // 删除员工方(多方),对对方没有影响
// Employee employee = (Employee) session.get(Employee.class,2);
// session.delete(employee);
// 删除部门方(一方)
// a, 如果没有关联的员工:能删除。
// b, 如果有关联的员工且inverse=true,由于不能维护关联关系,所以会直接执行删除,就会有异常
// c, 如果有关联的员工且inverse=false,由于可以维护关联关系,他就会先把关联的员工的外键列设为null值,再删除自己。
Department department = (Department) session.get(Department.class, 4);
session.delete(department);
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
}
级联:用于一对多,一对一;不用于多对多,多对一
<!--cascade属性:
默认为none,代表不级联。
级联是指操作主对象时,对关联的对象也做相同的操作。
可设为:delete, save-update, all, none ...-->
<set name="employees" cascade="delete">
<key column="departmentId"></key>
<one-to-many class="seu.xinci.relationship.one_many.pojo.Employee"></one-to-many>
</set>
维护关联关系:
对于一对多:
就是设置 外键列的值。
对于多对多:
就是插入或删除 中间表中的记录。
(2)、多对多关联关系
需要三张表,多出一张中间表,两个外键
Student.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.g_hbm_manyToMany">
<class name="Student" table="student">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"/>
<!-- teachers属性,Set集合。
表达的是本类与Teacher的多对多。
table属性:中间表(集合表)
key子元素:集合外键(引用当前表主键的那个外键)
-->
<set name="teachers" table="teacher_student" inverse="false">
<key column="studentId"></key>
<many-to-many class="Teacher" column="teacherId"></many-to-many>
</set>
</class>
</hibernate-mapping>
Teacher.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.g_hbm_manyToMany">
<class name="Teacher" table="teacher">
<id name="id">
<generator class="native"></generator>
</id>
<property name="name" type="string" column="name"/>
<!-- students属性,Set集合。
表达的是本类与Student的多对多。
-->
<set name="students" table="teacher_student" inverse="true">
<key column="teacherId"></key>
<many-to-many class="Student" column="studentId"></many-to-many>
</set>
</class>
</hibernate-mapping>
测试APP:
package cn.itcast.g_hbm_manyToMany;
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(Student.class)// 添加Hibernate实体类(加载对应的映射文件)
.addClass(Teacher.class)// 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
// 保存,有关联关系
@Test
public void testSave() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// 新建对象
Student student1 = new Student();
student1.setName("王同学");
Student student2 = new Student();
student2.setName("李同学");
Teacher teacher1 = new Teacher();
teacher1.setName("赵老师");
Teacher teacher2 = new Teacher();
teacher2.setName("蔡老师");
// 关联起来
student1.getTeachers().add(teacher1);
student1.getTeachers().add(teacher2);
student2.getTeachers().add(teacher1);
student2.getTeachers().add(teacher2);
teacher1.getStudents().add(student1);
teacher1.getStudents().add(student2);
teacher2.getStudents().add(student1);
teacher2.getStudents().add(student2);
// 保存
session.save(student1);
session.save(student2);
session.save(teacher1);
session.save(teacher2);
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 获取,可以获取到关联的对方
@Test
public void testGet() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// 获取一方,并显示另一方信息
Teacher teacher = (Teacher) session.get(Teacher.class, 3L);
System.out.println(teacher);
System.out.println(teacher.getStudents());
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 解除关联关系
@Test
public void testRemoveRelation() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// 如果inverse=false就可以解除,如果为true就不可以解除
Teacher teacher = (Teacher) session.get(Teacher.class, 3L);
teacher.getStudents().clear();
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 删除对象,对关联对象的影响
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// a, 如果没有关联的对方:能删除。
// b, 如果有关联的对方且inverse=false,由于可以维护关联关系,他就会先删除关联关系,再删除自己。
// c, 如果有关联的对方且inverse=true,由于不能维护关联关系,所以会直接执行删除自己,就会有异常。
Teacher teacher = (Teacher) session.get(Teacher.class, 9L);
session.delete(teacher);
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
}
单向关联:
单向多对一
单向一对多
单向多对多
3、对象的状态
临时状态测试(transient):与数据库没有对应,跟Session没有关联。
一般是新new出的对象。
Department department = new Department();
department.setName("研发部");
System.out.println(department.getId());
session.save(department);
System.out.println(department.getId());
刚开始得到的ID为null,后面得到的ID为11;
save()的过程就是将临时状态进行持久化!
持久化状态(Persist):
对象在Session的管理之中,最终会有对应的数据库记录。
特点:
(1)、有OID(唯一标识符)
(2)、对对象的修改会同步到数据库。
持久化状态(Persist):
对象在Session的管理之中,最终会有对应的数据库记录。
特点:
(1)、有OID(唯一标识符)
(2)、对对象的修改会同步到数据库。
在session内的代码:
//获取一方
Employee employee = (Employee) session.get(Employee.class, 9);
System.out.println(employee);
employee.setName("i");
会直接修改掉数据库中的数据
游离状态测试(Detached):
数据库中有对应记录,但对象不在Session管理之中。
修改此状态对象时数据库不会有变化。
删除状态(Removed):
执行了delete()后的对象。
删除状态(Removed):
执行了delete()后的对象。
- save():把临时状态变为持久化状态(交给Sessioin管理) 会生成:insert into ...
- update():把游离状态变为持久化状态 会生成:update ...
- saveOrUpdate():把临时或游离状态转为持久化状态 会生成:insert into 或 update ...
- delete():把持久化或游离转为删除状态 会生成:delete ...
- get():获取数据,是持久化状态 会生成:select ... where id=?
- load():获取数据,是持久化状态 会生成:select ... where
一、操作实体对象的
save()
update()
saveOrUpdate()
delete()
二、操作缓存的
clear()
evict() 驱逐单个对象
flush() 执行sql语句,提交事务默认先进行flush。save和查询get比较特殊会直接flush
三、查询实体对象的
get()
load()
createQuery()
createCriteria()
加载方式 返回值 如果数据不存在
------------------------------------------------------------------------------
get 立即加载 真实对象或null 返回null
load 延迟加载 代理对象 抛异常
save()
update()
saveOrUpdate()
delete()
二、操作缓存的
clear()
evict() 驱逐单个对象
flush() 执行sql语句,提交事务默认先进行flush。save和查询get比较特殊会直接flush
三、查询实体对象的
get()
load()
createQuery()
createCriteria()
加载方式 返回值 如果数据不存在
------------------------------------------------------------------------------
get 立即加载 真实对象或null 返回null
load 延迟加载 代理对象 抛异常
package cn.itcast.h_session_method;
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(User.class)// 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
// save():把临时状态变为持久化状态(交给Sessioin管理)
// 会生成:insert into ...
@Test
public void testSave() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = new User(); // 临时状态
user.setName("test");
session.save(user); // 变为了持久化状态
// --------------------------------------------
session.getTransaction().commit();
session.close();
user.setName("李四"); // 游离状态
System.out.println(user.getName()); // 游离状态
}
// update():把游离状态变为持久化状态
// 会生成:update ...
// 在更新时,对象不存在就报错
@Test
public void testUpdate() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = (User) session.get(User.class, 1);
System.out.println(user.getName()); // 持久化状态
// session.clear(); // 清除Session中所有的对象
session.evict(user); // 清除Session中一个指定的对象
user.setName("newname3");
session.update(user);
System.out.println("----");
// session.flush(); // 刷出到数据库
// --------------------------------------------
session.getTransaction().commit(); //
session.close();
}
// saveOrUpdate():把临时或游离状态转为持久化状态
// 会生成:insert into 或 update ...
// 在更新时,对象不存在就报错
// 本方法是根据id判断对象是什么状态的:如果id为原始值(对象的是null,原始类型数字是0)就是临时状态,如果不是原始值就是游离状态。
@Test
public void testSaveOrUpdate() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = new User();
user.setId(3); // 自己生成一个游离状态对象
user.setName("newName");
session.saveOrUpdate(user);
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// delete():把持久化或游离转为删除状态
// 会生成:delete ...
// 如果删除的对象不存在,就会抛异常
@Test
public void testDelete() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
// User user = (User) session.get(User.class, 2); // 持久化
User user = new User();
user.setId(300);
session.delete(user);
session.flush();
System.out.println("---");
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// get():获取数据,是持久化状态
// 会生成:select ... where id=?
// 会马上执行sql语句
// 如果数据不存在,就返回null
@Test
public void testGet() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = (User) session.get(User.class, 5); // 持久化
System.out.println(user.getClass());
// System.out.println("---");
// System.out.println(user.getName());
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// load():获取数据,是持久化状态
// 会生成:select ... where id=?
// load()后返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
// 让懒加载失效的方式:一、把实体写成final的;二、在hbm.xml中写<class ... lazy="false">
// 不会马上执行sql语句,而是在第1次使用非id或class属性时执行sql。
// 如果数据不存在,就抛异常:ObjectNotFoundException
@Test
public void testLoad() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
User user = (User) session.load(User.class, 5);
System.out.println(user.getClass());
System.out.println("---");
System.out.println(user.getId());
System.out.println(user.getName());
// System.out.println(user.getName());
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
// 操作大量数据,要防止Session中对象过多而内存溢出
@Test
public void testBatchSave() throws Exception {
Session session = sessionFactory.openSession();
session.beginTransaction();
// --------------------------------------------
for (int i = 0; i < 30; i++) {
User user = new User();
user.setName("测试");
session.save(user);
if (i % 10 == 0) {
session.flush(); // 先刷出
session.clear(); // 再清空
}
}
// --------------------------------------------
session.getTransaction().commit();
session.close();
}
}
4、回顾
一、集合映射。类型 Java中声明 映射元素
-------------------------------------------------------
Set Set <set>
List List <list>
Map Map <map>
数组 ...[] <array>
Bag List/Collection <bag>
--------------------------------------------------------
要说明的信息有:
1,只要有集合,就一定有集合表。
2,集合外键。
3,集合元素。
4,对于List和数组,还需要多一个索引列。
5,对于Map,还需要多一个key列。
值类型的集合。
实体类型的集合。
二、关联关系映射(要说明的信息有什么)。
一对多:
1,属性名
2,集合外键
3,关联的实体类型(one-to-many class="")
多对一:
1,属性名
2,外键列名
3,关联的实体类型
多对多:
1,属性名
2,中间表
3,集合外键:引用当前对象表主键值的那外外键
4,关联的实体类型
5,另一个外键:引用关联实体表主键的那个外键。
一些重要的属性:
inverse:
是否放弃维护关联关系。
默认是false,表示可以维护。
实体类型的集合映射中可以使用(一对多、多对多)。
sort:
在内存中排序(类似于TreeSet)
默认为unsorted,即不排序。
在无序的集合映射中可以使用。
order-by:
使用数据库排序,即在SQL中增加orderby子句(类似于LinkedHashSet)。
默认不排序,这里指定的是sql语句中的orderby子句。
在无序的集合映射中可以使用。
cascade:
级联。
默认为none。
在所有的关联关系映射中可以使用。
常用的值:all, save-update, delete, none.
三、Session中的方法。
对象的状态:
Session中 数库中
---------------------------------------------------
临时 无 无
持久化 有 最终会有
游离 无 有
删除 调用了delete()方法后
1,操作实体对象的
save()
update()
saveOrUpdate()
delete()
2,操作缓存的
clear() 清空Session缓存,不会执行sql语句。
evict()
flush() 马上执行sql语句,不会清楚Session缓存。
3,查询实体对象的
get()
load()
createQuery()
createCriteria()
---------------------------------------------------
临时 无 无
持久化 有 最终会有
游离 无 有
删除 调用了delete()方法后
1,操作实体对象的
save()
update()
saveOrUpdate()
delete()
2,操作缓存的
clear() 清空Session缓存,不会执行sql语句。
evict()
flush() 马上执行sql语句,不会清楚Session缓存。
3,查询实体对象的
get()
load()
createQuery()
createCriteria()