A. Hibernate执行环境配置
- 用到的包
antlr-2.7.6.jar 解释hibernate的查询语言,叫hibernate query Language,叫hql语句的 commons-collections-3.1.jar 是一些集合,一些公共的集合,apache 的 公共包, 主要是支持hibernate缓存的,hibernate有各种缓存,一级缓存,二级缓存,查询缓存 dom4j-1.6.1.jar 解析xml文件的 hibernate3.jar 核心包 javassist-3.11.0.GA.jar 生成一些动态代理的包 jta-1.1.jar java事物管理,事物分布式管理 log4j-1.2.17.jar slf4j-api-1.5.8.jar jpos的日志接口,jpos是自己的产品,一般用的并不多,用的几乎都是log4j,为什么hibernate用它?可能是gemkey被jpos收编了之后,换本家了总得用点自己的东西,3.5以下需要 slf4j-log4j12-1.5.8.jar slf4j-api的实现类,没有实现完的
- 类路径下的log4j.properties
log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n log4j.rootLogger=warn, stdout
- 类路径下的hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- session工厂 --> <session-factory> <!-- 链接数据库4大参数 --> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <!-- ?createDatabaseIfNotExist=true数据库不存在时自动创建 --> <property name="hibernate.connection.url"> jdbc:mysql://127.0.0.1:3306/hibernate?createDatabaseIfNotExist=true</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">123</property> <!-- 数据库方言 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <!-- 显示sql语句 --> <property name="hibernate.show_sql">true</property> <!-- 格式化sql语句 <property name="hibernate.format_sql">true</property> --> <!-- 从映射文件到数据库定义语言 ,参数create会删除原来的表,update更新, 配置自动根据映射文件更新数据库表 --> <property name="hbm2ddl.auto">update</property> </session-factory> </hibernate-configuration>
B. 创建实体类及映射文件
- User.java
private Integer id; private String username; private char sex; private Date birthday; private Integer age; private double salary;// 薪资 //各种set、get方法
- User.hbm.xml
放在User.java同一个包下
<?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> <!-- 表名跟类名一样时可以省略 table属性 --> <class name="com.ashmit.model.User" table="T_USER"> <!-- 配置列 --> <id name="id"> <!-- generator:指定主键生成策略 --> <!--native:由数据库生成主键 --> <!--<generator class="native" /> --> <!-- increment:由hibernate生成主键,每次去数据库中查询出最大值加1 --> <generator class="increment" /> </id> <property name="username" /> <property name="sex" /> <property name="birthday" /> <property name="age" /> <property name="salary" /> </class> </hibernate-mapping>
- 在hibernate.cfg.xml中配置
<session-factory> …… <!-- 配置实体映射文件(或实体类) --> <mapping resource="com/ashmit/model/User.hbm.xml" /> </session-factory>
C. Hibernate五大API
- 测试Hibernate的五大API:
Hibernate五大API:Configuration,SessionFactory,Session,Transaction,Query
public class HibernateTest { private Configuration cfg = null; private SessionFactory factory = null; private Session session = null; private Transaction trans = null; @Before public void setUp() throws Exception { // 解析hibernate.cfg.xml配置文件 (.configure()后才会真正解析) cfg = new Configuration().configure(); // 创建SessionFactory(创建连接池) factory = cfg.buildSessionFactory(); // 创建Session session = factory.openSession(); } /** * 增加 */ @Test public void testAdd() { User user = new User(); user.setUsername("张三"); user.setSex('男'); user.setAge(20); user.setBirthday(new Date()); user.setSalary(2000.28); try { // 创建及开启事务对象 trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); } catch (HibernateException e) { // 回滚事务 trans.rollback(); e.printStackTrace(); } } /** * 测试Query接口,查询所有 */ @Test public void testFindAll() { Query query = session.createQuery("from User"); List<User> list = query.list(); for (int i = 0; i < list.size(); i++) { User user = list.get(i); System.out.println("名字:" + user.getUsername()); System.out.println("生日:" + user.getBirthday()); } } /** * 根据ID更新 */ @Test public void testUpdate() { try { // // 创建及开启事务对象 // trans = session.beginTransaction(); // // ..... // User user = (User) session.get(User.class, 5); // user.setUsername("李四"); // user.setSex('女'); // session.update(user);// 多余,可以不写 // // trans.commit(); // 创建及开启事务对象 trans = session.beginTransaction(); // ..... User user = (User) session.get(User.class, 6); user.setUsername("赵六"); user.setSex('女'); trans.commit(); } catch (HibernateException e) { // 回滚事务 trans.rollback(); e.printStackTrace(); } } /** * 根据ID删除 */ @Test public void testDelete() { try { // 创建及开启事务对象 trans = session.beginTransaction(); // ..... User user = (User) session.get(User.class, 2); session.delete(user); trans.commit(); } catch (HibernateException e) { // 回滚事务 trans.rollback(); e.printStackTrace(); } } /** * 根据ID查询(只有查询不需要开启事务) */ @Test public void testLoad() { User user = (User) session.get(User.class, 6); System.out.println("名字:" + user.getUsername()); System.out.println("生日:" + user.getBirthday()); } @After public void tearDown() throws Exception { if (session != null) { session.close(); } }
- 单例SessionFactory工厂支持类
HibernateUtil.java
/** * 单例SessionFactory * SessionFactory就是保存配置、缓存的 */ public class HibernateUtil { private static Configuration cfg = null; private static SessionFactory factory = null; // 静态代码块先执行 static { if (cfg == null) { // 解析hibernate.cfg.xml配置文件 (.configure()后才会真正解析) cfg = new Configuration().configure(); } if (factory == null) { // 创建SessionFactory(创建连接池) factory = cfg.buildSessionFactory(); } } /** * 获取session工厂 * * @return */ public static SessionFactory getFactory() { return factory; } /** * 打开一个session * * @return */ public static Session getSession() { return factory.openSession(); } /** * 关闭session * * @param session */ public static void closeSession(Session session) { if (session != null) { session.close(); } } }
D. 持久化对象的三种状态
private Session session = null; private Transaction trans = null; @Test public void testAdd() { // [new]瞬时对象 User user = new User(); user.setUsername("王二"); user.setSex('女'); user.setAge(23); user.setBirthday(new Date()); user.setSalary(3000.56); try { // 创建Session session = HibernateUtil.getSession(); // 创建及开启事务对象 trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); // 持久化对象:对象有id值,与数据库同步(受事务、session的管理), // 对象的引用要在session的缓存当中 } catch (HibernateException e) { // 回滚事务 trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } // 离线/托管对象,有id值,不受数据库管理(session关闭之后持久化对象变为离线/托管对象) System.out.println(user.getUsername()); user.setUsername("王麻子"); // 将离线/托管对象重新拉入到缓存中,重新与数据库关联起来 try { // 创建Session session = HibernateUtil.getSession(); trans = session.beginTransaction(); session.update(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
E. 增、删、改、查各方法的区别
- Persist和Save及Save和SaveOrUpdate方法的区别
private Session session = null; private Transaction trans = null; // Save和SaveOrUpdate方法的区别 @Test public void testSaveAndSaveOrUpdate() { User user = new User(); user.setUsername("王二的范德萨方麻子"); user.setSex('男'); user.setAge(20); user.setBirthday(new Date()); user.setSalary(3000.56); user.setId(5); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // 无论如何也会存起来,如果配置文件id由hibernate来生成 // ( <generator class="increment" />),设置id没用,hibernate自动生成 // session.save(user); // 有id就会更新,但是数据库中没有当前id的数据就会抛异常,没有id就会保存 session.saveOrUpdate(user); // session.persist(user)和.save(user);几乎没有区别,有id值会抛异常 trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } // Save和SaveOrUpdate方法对持久化对象不起作用 @Test public void testSaveAndSaveOrUpdate2() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // user是一个持久对象 User user = (User) session.get(User.class, 6); user.setUsername("赵六"); // 数据不一致就会更新 // session.save(user); // 数据不一致也会更新 session.saveOrUpdate(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- Merge和Update方法的区别
private Session session = null; private Transaction trans = null; // update和merge方法的区别 @Test public void testUpdateAndMerge() { User user = new User(); user.setUsername("东方东方打df算可风"); user.setSex('男'); user.setAge(44); user.setBirthday(new Date()); user.setSalary(548548.56); user.setId(5); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ... User u = (User) session.get(User.class, 5); // session.update(user); // 在session缓存中有两个相同ID的实体时,更新会抛异常 session.merge(user); // 跟update不一样,merge方法会把 要持久化的对象赋值给ID相同的实体对象 trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- Lock(已淘汰)和Update方法的区别
private Session session = null; private Transaction trans = null; // Update和Lock(淘汰)方法的区别 @Test public void testUpdateAndLock() { User user = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); user = (User) session.get(User.class, 6); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println(user); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // lock方法的作用就是将没有改变属性的离线、托管对象重新拉入到持久对象当中 // 但是如果改了属性值,就得用update方法 session.lock(user, LockMode.OPTIMISTIC); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- Save、Update、Delete方法的执行顺序及flush方法
private Session session = null; private Transaction trans = null; // 命令的执行顺序 @Test public void testSessionOnFlush() { User user = new User(); user.setUsername("李四"); user.setSex('男'); user.setAge(44); user.setBirthday(new Date()); user.setSalary(548548.56); // user.setId(5); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ... User u = (User) session.get(User.class, 1); // 不执行flush()方法在提交后的发出的sql语句的默认顺序就是:查、曾、改、删 // 执行flush()方法会提前发出sql语句,然后刷新缓存 u.setUsername("王麻子"); session.flush(); session.delete(session.get(User.class, 4)); session.flush(); session.save(user); session.flush(); user = new User(); user.setUsername("赵六"); user.setSex('男'); user.setAge(44); user.setBirthday(new Date()); user.setSalary(548548.56); session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- close、clear及evict方法的区别
private Session session = null; private Transaction trans = null; // close()、clear()和evict()方法 @Test public void testClearAndEvict() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); Query query = session .createQuery("from com.alyshen.hibernate.domain.User"); List<User> list = query.list(); // session.clear();// // 清空缓存,查询出来的对象都变成离线、托管对象的了,拉入缓存则需要:session.update(user); int i = 0; for (User user : list) { i++; if (i == 5) { session.evict(user);// 驱逐 } user.setUsername(user.getUsername() + "_X"); // session.update(user); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { //close();session直接被回收 HibernateUtil.closeSession(session); } }
- get和load方法的区别
private Session session = null; private Transaction trans = null; // get()和load()方法的区别 @Test public void testGetAndLoad() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // User user = (User) session.get(User.class, 11); User user = (User) session.load(User.class, 11); // 懒加载,创建的是一个对象的代理,如果查询出来为空则创建不了代理就抛异常 // 如果不需要懒加载,则可以在实体映射文件配置中配置:lazy="false",配置后跟使用get一样, //只有在使用对象的时候,用对象的代理对象发出sql语句 System.out.println(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- list和iterator方法的区别
private Session session = null; private Transaction trans = null; // list()和iterator()方法 @Test public void testListAndIterator() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); Query query = session.createQuery("from User"); // list()全部查询出来,无法利用缓存 List<User> list = query.list(); for (User user : list) { System.out.println("用户名:" + user.getUsername()); } // list = query.list(); // // for (User user : list) { // System.out.println("用户名:" + user.getUsername()); // } // 先把所有id查询出来,然后有id去单个的查询,可以利用缓存 Iterator<User> iter = query.iterate(); while (iter.hasNext()) { User user = iter.next(); System.out.println("用户名:" + user.getUsername()); } //理想是方式就是先用list查出来,再用的话就用iterate // iter = query.iterate(); // while (iter.hasNext()) { // User user = iter.next(); // System.out.println("用户名:" + user.getUsername()); // } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
F. 主键生成策略
- 常用主键生成策略
User.hbm.xml
<id name="id"> <!-- 指定主键生成策略 assigned:没有生成策略 increment:由Hibernate生成主键,每次去数据库中查询出最大值加1 native:由数据库生成主键 identity:由数据库生成主键 hilo:生成一个hibernate_unique_key表,保存高位值,hibernate提供低位值 <generator class="hilo"> 设置参数 <param name="table">hibernate_key</param> <param name="column">next_value</param> </generator> uuid:可能一亿年重复一次 <generator class="uuid"/> --> <generator class="increment"/> </id>
- 联合主键生成策略(不常用)
- UserKey.java
public class UserKey implements Serializable { private int id; private String uuid; /** * 重写hashCode方法 */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((uuid == null) ? 0 : uuid.hashCode()); return result; } /** * 重写equals方法 */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; UserKey other = (UserKey) obj; if (id != other.id) return false; if (uuid == null) { if (other.uuid != null) return false; } else if (!uuid.equals(other.uuid)) return false; return true; } public UserKey(int id, String uuid) { super(); this.id = id; this.uuid = uuid; } public UserKey() { super(); // TODO Auto-generated constructor stub } //各种set、get方法 …… }
a) User.java
private UserKey id; private String username; private char sex; private Date birthday; private int age; private double salary;// 薪资 //各种set、get方法 ……
b) User.hbm.xml
<composite-id name="id" class="UserKey"> <key-property name="id"/> <key-property name="uuid"/> </composite-id>
c) 测试联合主键
private Session session = null; private Transaction trans = null; /** * 测试联合主键 */ @Test public void testStrategy() { User user = new User(); user.setUsername("赵六"); user.setSex('女'); user.setAge(17); user.setBirthday(new Date()); user.setSalary(20000.56); user.setId(new UserKey(12, "zhaoliou")); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } @Test public void testLoad() { session = HibernateUtil.getSession(); User user = (User) session.get(User.class, new UserKey(12, "zhaoliou")); System.out.println(user.getUsername()); }
G. 属性的映射
- User.java
private int id; private String username; private String user; private char sex; private Date birthday; private int age; private double salary;// 薪资 private String story;// 小说 private byte[] music = null; //各种set、get方法 ……
- User.hbm.xml
<class name="User" table="T_USER" lazy="true"> <id name="id"> <generator class="increment" /> </id> <!-- name="username" 对应类名的属性名称 not-null="true" 非空 type="string" 类型 length="50" 长度 column="_user" 对应的表列名 update="false" 更新不了 insert="false" 添加不了 unique="true" 唯一约束 access="field" 事务提交时访问对象的字段,而不是set、get方法 ,破坏封装 --> <property name="username" type="string" length="50" /> <property name="user" column="_user" /> <property name="sex" type="character" length="2" /> <property name="birthday" /> <property name="age" /> <property name="salary" /> <property name="story" type="text" /> <!-- 默认是1k,类型blob最多100k,所以要用字节binary,长度90M --> <property name="music" type="binary" length="9437184" /> </class>
- 测试
private Session session = null; private Transaction trans = null; /** * 测试映射配置 */ @Test public void testProperty() { User user = new User(); user.setUsername("赵六"); user.setSex('女'); user.setAge(17); user.setBirthday(new Date()); user.setSalary(20000.56); // user.setId(20); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试不能添加、更新属性的映射配置 */ @Test public void testUpdate() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... User user = (User) session.get(User.class, 1); user.setUsername("李四"); user.setSex('男'); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试长字符串 */ @Test public void testStoryTypeText() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... User user = new User(); user.setUsername("赵六"); user.setSex('女'); user.setAge(17); user.setBirthday(new Date()); user.setSalary(20000.56); user.setStory("附近的扩军绿军军军军军军军军军军军军军豆腐干看见对方考虑更多附近 都是"); session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 存入文件 */ @Test public void testMusicTypeBinary() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... User user = new User(); user.setUsername("赵六"); user.setSex('女'); user.setAge(17); user.setBirthday(new Date()); user.setSalary(20000.56); user.setStory("sfdsfkdsfdskfjkldsfdjsklfjdksjfld"); try { user.setMusic(FileUtils.readFileToByteArray(new File( "E:\\爱音乐\\经典金曲\\Linda - 张学友.mp3"))); } catch (IOException e) { // TODO Auto-generated catch block throw new RuntimeException(e); } session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 取出文件 */ @Test public void testMusicTypeBinary2() { session = HibernateUtil.getSession(); User user = (User) session.get(User.class, 2); try { FileUtils.writeByteArrayToFile(new File("e:/Linda.mp3"), user.getMusic()); } catch (IOException e) { // TODO Auto-generated catch block throw new RuntimeException(e); } }
H. 关联映射配置
理解OR映射的异构和多重性
组里有联系人的引用且联系人里有组的引用叫双向关联,找到其中一方就能找到对方
联系人到组的单向关联,联系人保存组的引用,找到联系人就能找到组,但找到组是不能找到联系人的
组到联系人的单向关联,组保存联系人的引用,找到组就能找到联系人,但找到联系人是不能不到组的
a) 多对一
组里有多个联系人,联系人只有一个组,叫多对一
ContactPerson.java
public class ContactPerson { private Group group; //各种set、get方法 …… }
Group.java
public class Group { private Set<ContactPerson> contactPersons = new HashSet<ContactPerson>(); //各种set、get方法 …… }
b) 一对一
一个联系人有一个账号,一个账号对应一个联系人,叫一对一
Account.java
public class Account { private ContactPerson person; //各种set、get方法 …… }
ContactPerson.java
public class ContactPerson { private Account account; //各种set、get方法 …… }
c) 多对多
一个学生有多个老师,一个老师有多个学生,叫多对多
Student.java
public class Student { private Set<Teacher> teachers = new HashSet<Teacher>(); //各种set、get方法 …… }
Teacher.java
public class Teacher { private Set<Student> students = new HashSet<Student>(); //各种set、get方法 …… }
多对一单向关联
a) 多对一单向关联的映射配置
1) Group.java
public class Group { private int id; private String groupName; //各种set、get方法 …… }
2) Group.hbm.xml
<!-- 可以指定包名 --> <hibernate-mapping package="com.alyshen.hibernate.domain"> <class name="Group" table="t_group"> <id name="id"> <generator class="increment" /> </id> <property name="groupName" /> </class> </hibernate-mapping> 3) ContactPerson.java public class ContactPerson { private int id; private String name; private Group group; //各种set、get方法 …… }
4) ContactPerson.hbm.xml
<class name="ContactPerson" table="T_contactPerson"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- lazy="false" 立即把联系人的组查出来,不懒加载了 lazy="proxy" 使用代理,延迟加载 (默认的) lazy="no-proxy" 不使用代理,但加了没用,本质还是使用代理的, 使用这个需要类增强工具提高性能才有用 --> <many-to-one name="group" column="groupId" /> </class> 5) 测试 private Session session = null; private Transaction trans = null; /** * Many2One单向关联 */ @Test public void testMany2OneAdd() { Group group = new Group(); group.setGroupName("同学"); ContactPerson p1 = new ContactPerson(); p1.setName("张三"); p1.setGroup(group); ContactPerson p2 = new ContactPerson(); p2.setName("李四"); p2.setGroup(group); ContactPerson p3 = new ContactPerson(); p3.setName("王五"); p3.setGroup(group); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(group); //先存组,保存联系人时才能一起将联系人的组信息保存 session.save(p1); session.save(p2); session.save(p3); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 多对一单向关联中的懒加载机制
private Session session = null; private Transaction trans = null; /** * Many2One单向关联 */ @Test public void testMany2OneQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 1); // ContactPerson p = (ContactPerson) // session.load(ContactPerson.class, // 1); System.out.println(person.getName()); // p.getGroup()此时的group是一个代理对象,在用它的属性的时候代理对象才会发出sql查询 // 不需要代理可以在多对一配置中配置不懒加载:lazy="false"; System.out.println(person.getGroup().getGroupName()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * Many2One延迟加载异常 */ @Test public void testMany2OneQuery2() { ContactPerson person = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... person = (ContactPerson) session.get(ContactPerson.class, 1); // person = (ContactPerson) session.load(ContactPerson.class, 1); System.out.println(person.getName()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } // 这时联系人的组是一个代理对象,想得到它的名字时需要发出sql查询,但这时session已经关闭,所以会抛延迟加载异常 // 如果配置多对一时配置:lazy="false"立即加载就不会抛延迟加载异常了,但是person必须也是立即加载 // 也就是说懒加载session必须要开着的,链接要开着的 System.out.println(person.getGroup().getGroupName()); }
c) 多对一单向关联的级联配置
1) ContactPerson.hbm.xml
<!-- cascade="none":不级联(默认) cascade="save-update":保存和更新级联 cascade="delete":删除级联 cascade="all":都级联 --> <many-to-one name="group" column="groupId" cascade="all" />
2) 测试级联添加及删除
private Session session = null; private Transaction trans = null; /** * 级联添加 */ @Test public void testCascadeAdd() { Group group = new Group(); group.setGroupName("同学"); ContactPerson p1 = new ContactPerson(); p1.setName("张三"); p1.setGroup(group); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(p1); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 级联删除 */ @Test public void testCascadeDelete() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 1); session.delete(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
3) 级联删除外键约束
private Session session = null; private Transaction trans = null; /** * 级联删除外键约束 */ @Test public void testCascadeDelete2() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 5); // person的组还有其他联系人时,级联删除就会抛异常,因为外键约束 session.delete(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
4) 利用离线对象执行删除操作时,级联配置失效
private Session session = null; private Transaction trans = null; /** * 利用离线对象执行删除操作时,级联配置失效 */ @Test public void testCascadeDelete3() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... ContactPerson person = new ContactPerson(); person.setId(5);// 创建离线对象 session.delete(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
一对多单向关联
a) 一对多单向关联配置
1) ContactPerson.java
private int id; private String name; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ContactPerson other = (ContactPerson) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } //各种set、get方法 ……
2) ContactPerson.hbm.xml
<class name="ContactPerson" table="t_person"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> </class> 3) Group.java private int id; private String groupName; private Set<ContactPerson> persons = new HashSet<ContactPerson>(); //各种set、get方法 ……
4) Group.hbm.xml
<class name="Group" table="t_group"> <id name="id"> <generator class="increment" /> </id> <property name="groupName" /> <!-- cascade="all" 级联全部操作 lazy="false" 不懒加载 --> <set name="persons" cascade="all" lazy="false"> <key column="groupId" /> <one-to-many class="ContactPerson" /> </set> </class> 5) 添加及查询 private Session session = null; private Transaction trans = null; /** * 一对多单向关联——添加 */ @Test public void testOne2ManyAdd() { Group group = new Group(); group.setGroupName("同学"); ContactPerson p1 = new ContactPerson(); p1.setName("张三"); ContactPerson p2 = new ContactPerson(); p2.setName("李四"); ContactPerson p3 = new ContactPerson(); p3.setName("王五"); group.addPerson(p1); group.addPerson(p2); group.addPerson(p3); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 多余的更新sql语句没法去掉 session.save(p1); session.save(p2); session.save(p3); session.save(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 一对多单向关联——查询数据 */ @Test public void testOne2ManyQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 1); System.out.println(person.getName()); Group group = (Group) session.get(Group.class, 1); Iterator<ContactPerson> iter = group.getPersons().iterator(); while (iter.hasNext()) { System.out.println(iter.next().getName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
a) 一对多关联的重建和级联操作
1) 级联添加
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——级联添加 */ @Test public void testOne2ManyCascadeAdd2() { Group group = new Group(); group.setGroupName("同事"); ContactPerson p1 = new ContactPerson(); p1.setName("王二"); ContactPerson p2 = new ContactPerson(); p2.setName("麻子"); ContactPerson p3 = new ContactPerson(); p3.setName("赵六"); group.addPerson(p1); group.addPerson(p2); group.addPerson(p3); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
2) 级联删除
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——级联删除 */ @Test public void testOne2ManyCascadeDelete() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = (Group) session.get(Group.class, 2); session.delete(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
3) 离线对象级联删除失效
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——离线对象级联删除失效 */ @Test public void testOne2ManyCascadeDelete2() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = new Group(); group.setId(1);// 创建离线对象 session.delete(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
a) 一对多关联的延迟加载、修改、删除及清空
1) 不懒加载
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——不懒加载 */ @Test public void testOne2ManyLazyDoFalse() { Group group = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... group = (Group) session.get(Group.class, 2); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println(group.getGroupName()); for (ContactPerson person : group.getPersons()) { System.out.println(person.getName()); } }
2) 修改
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——修改 */ @Test public void testOne2ManyUpdate() { Group group = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... group = (Group) session.get(Group.class, 2); ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 1); group.addPerson(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println(group.getGroupName()); for (ContactPerson person : group.getPersons()) { System.out.println(person.getName()); } }
3) 从组里清除
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——从组里清除 */ @Test public void testOne2ManyRemove() { Group group = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... group = (Group) session.get(Group.class, 2); ContactPerson person = (ContactPerson) session.get( ContactPerson.class, 4); group.getPersons().remove(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println(group.getGroupName()); for (ContactPerson person : group.getPersons()) { System.out.println(person.getName()); } }
4) 清空组
private Session session = null; private Transaction trans = null; /** * 一对多单向关联——清空组 */ @Test public void testOne2ManyClear() { Group group = null; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... group = (Group) session.get(Group.class, 2); group.getPersons().clear(); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println(group.getGroupName()); for (ContactPerson person : group.getPersons()) { System.out.println(person.getName()); } }
b) 聪明的extra(推荐一对多延迟加载策略)
1) Group.hbm.xml
<!-- lazy="extra" 根据情况发出更好的 sql语句 --> <set name="persons" cascade="all" lazy="extra"> <key column="groupId" /> <one-to-many class="ContactPerson" /> </set>
2) 测试Extra
private Session session = null; private Transaction trans = null; /** * 这个测试Extra和普通延迟加载没区别 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = (Group) session.get(Group.class, 1); System.out.println(group.getGroupName()); for (ContactPerson p : group.getPersons()) { System.out.println(p.getName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 这个测试Extra加载获取条数 */ @Test public void testQueryCount() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = (Group) session.get(Group.class, 1); // 普通延迟加载就会把联系人全部查出来,再算大小 // 而extra加载直接去查条数 System.out.println(group.getGroupName() + "组里有联系人:" + group.getPersons().size() + "个!"); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 这个测试Extra加载是否包含某个联系人 */ @Test public void testCheckContains() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = (Group) session.get(Group.class, 1); ContactPerson p = new ContactPerson(); p.setId(3); //普通懒加载加载为false,extra懒加载为true System.out.println(group.getPersons().contains(p)); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
一对多双向关联
a) 一对多双向关联及inverse的用法
1) Group.java
private int id; private String groupName; private Set<ContactPerson> persons = new HashSet<ContactPerson>(); //各种set、get方法 …… 2) Group.hbm.xml <class name="Group" table="t_group"> <id name="id"> <generator class="increment" /> </id> <property name="groupName" /> <!— inverse="true":我的一端放弃了维护数据的统一,由多的一端维护数据的统一, 加了我的数据,我就不管别的了,就不会更新别人的数据了 --> <set name="persons" cascade="all" lazy="extra" inverse="true"> <key column="groupId" /> <one-to-many class="ContactPerson" /> </set> </class>
3) ContactPerson.java
private int id; private String name; private Group group; @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ContactPerson other = (ContactPerson) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } //各种set、get方法 ……
4) ContactPerson.hbm.xml
<class name="ContactPerson" table="t_person"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- column要一致,不然会有错 --> <many-to-one name="group" column="groupId" cascade="all" /> </class>
5) 测试一对多双向关联
private Session session = null; private Transaction trans = null; /** * 一对多双向关联,由一的一端维护数据,所以多的一端多了update语句 */ @Test public void testOne2ManyAdd() { Group group = new Group(); group.setGroupName("同学"); ContactPerson p1 = new ContactPerson(); p1.setName("张三"); ContactPerson p2 = new ContactPerson(); p2.setName("李四"); ContactPerson p3 = new ContactPerson(); p3.setName("王五"); group.addPerson(p1); group.addPerson(p2); group.addPerson(p3); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 一对多双向关联,由多的一端维护数据 */ @Test public void testOne2ManyAdd2() { Group group = new Group(); group.setGroupName("同事"); ContactPerson p1 = new ContactPerson(); p1.setName("王二"); ContactPerson p2 = new ContactPerson(); p2.setName("麻子"); ContactPerson p3 = new ContactPerson(); p3.setName("赵六"); p1.setGroup(group); p2.setGroup(group); p3.setGroup(group); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(p1); session.save(p2); session.save(p3); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
6) inverse的用法
private Session session = null; private Transaction trans = null; /** * 一对多双向关联,由两端维护数据,多了update语句 * ,set集合的inverse="true":一的一端放弃维护数据的统一,只有添加sql语句, * 一的一端不再更新其他有关联的数据 */ @Test public void testOne2ManyAdd3() { Group group = new Group(); group.setGroupName("朋友"); ContactPerson p1 = new ContactPerson(); p1.setName("李三"); ContactPerson p2 = new ContactPerson(); p2.setName("王五"); ContactPerson p3 = new ContactPerson(); p3.setName("赵七"); p1.setGroup(group); p2.setGroup(group); p3.setGroup(group); group.addPerson(p1); group.addPerson(p2); group.addPerson(p3); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(group); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 一对多双向关联重建及外键定义不一致导致的问题
1) 关联重建
private Session session = null; private Transaction trans = null; /** * 测试一对多双向关联关联重建 */ @Test public void testOne2ManyQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Group group = (Group) session.get(Group.class, 2); System.out.println(group.getGroupName() + "当中有元素:"); for (ContactPerson person : group.getPersons()) { System.out.println(person.getName() + ",所属组:" + person.getGroup().getGroupName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
2) 外键定义不一致导致的问题
<!-- column名要一致,不然会在t_person中生成两个不一致的组id,数据要双向维护, 不然没有值的组id用来查询就获取不到数据 --> <many-to-one name="group" column="groupId" cascade="all" />
c) 一对多双向自关联
1) Employee.java
private int id; private String name; private Employee manager; private Set<Employee> puisnes = new HashSet<Employee>(); @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } //各种set、get方法 ……
2) Employee.hbm.xml
<class name="Employee" table="t_emp"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <many-to-one name="manager" column="managerId" cascade="all" lazy="false" /> <!-- inverse="true":我本不维护数据的统一性,你(puisnes)下级添加就可以 了 --> <set name="puisnes" cascade="all" inverse="true" lazy="extra"> <key column="managerId" /> <one-to-many class="Employee" /> </set> </class> 在hibernate.cfg.xml文件中在注明一下: <session-factory> …… <mapping resource="com/yuze/zihe/hibernate/domain/Employee.hbm.xml" /> </session-factory>
3) 测试一对多自关联
private Session session = null; private Transaction trans = null; /** * 一的一端放弃维护数据 */ @Test public void testAddEmployee() { /** * 员工加上司,存底层员工 */ Employee root = new Employee(); root.setName("董事长"); Employee manager1 = new Employee(); manager1.setName("周总"); Employee manager2 = new Employee(); manager2.setName("王总"); Employee e1 = new Employee(); e1.setName("张三"); Employee e2 = new Employee(); e2.setName("李四"); Employee e3 = new Employee(); e3.setName("王五"); Employee e4 = new Employee(); e4.setName("赵六"); Employee e5 = new Employee(); e5.setName("周七"); Employee e6 = new Employee(); e6.setName("王二"); // root.addPuisne(manager1); // root.addPuisne(manager2); // 上司加下属没用,因为上司放弃维护数据(一的一端放弃维护数据) e1.setManager(manager1); e2.setManager(manager1); e3.setManager(manager1); e4.setManager(manager1); e5.setManager(manager2); e6.setManager(manager2); manager1.setManager(root); manager2.setManager(root); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // session.save(root); // 这时存root没用,因为一的一端已经放弃维护数据 session.save(e1); session.save(e2); session.save(e3); session.save(e4); session.save(e5); session.save(e6); // 多的一方维护数据 trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
4) 一对多自关联的重建
private Session session = null; private Transaction trans = null; /** * 一对多自关联——重建 */ @Test public void testQueryEmployee() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Employee root = (Employee) session.get(Employee.class, 3); out(root, 1); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 通过递归算法重建(递归算法要有结束循环的条件) * @param e * @param level */ private void out(Employee e, int level) { if (e != null) { for (int i = 0; i < level; i++) { System.out.print(" "); } System.out.println(level + "级:" + e.getName()); if (e.getPuisnes() != null && e.getPuisnes().size() > 0) { for (Employee e1 : e.getPuisnes()) { out(e1, level + 1); } } } }
一对一关联
a) 一对一共享主键关联
1) Employee.java
private int id; private String name; // 加了user属性就是一对一双向关联 ,没有user属性就是单向关联 private User user; //各种set、get方法 ……
2) Employee.hbm.xml
<class name="Employee" table="t_employee"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- 加了user属性就是一对一双向关联 ,没有user属性就是单向关联 --> <one-to-one name="user" cascade="all" /> </class> 3) User.java private int id; private String username; private String password; private Employee emp; //各种set、get方法 ……
4) User.hbm.xml
<class name="User" table="T_USER"> <!-- 用户主键共享员工的主键id --> <id name="id"> <generator class="foreign"> <param name="property">emp</param> </generator> </id> <property name="username" /> <property name="password" /> <!-- constrained:受约束的 ,只有我被删除了,你才能被删除,有我在你就删除不了 --> <one-to-one name="emp" constrained="true" cascade="all" /> </class>
5) 测试一对一共享主键关联
private Session session = null; private Transaction trans = null; /** * 一对一单向关联及双向关联 */ @Test public void testAdd2() { Employee emp = new Employee(); emp.setName("赵六"); User user = new User(); user.setUsername("zhaoliou"); user.setPassword("123456"); user.setEmp(emp); // emp.setUser(user);双向关联时用不了,会抛异常 try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 一对一双向关联关联重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Employee emp = (Employee) session.get(Employee.class, 1); System.out.println("员工名:" + emp.getName() + ",员工账号:" + emp.getUser().getUsername()); System.out.println("员工名:" + emp.getUser().getEmp().getUser().getEmp().getName()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 一对一唯一外键关联
1) Employee.hbm.xml
<class name="Employee" table="t_employee"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- 没有user属性是单向关联,加了user属性就是双向关联了 property-ref="emp": employee引用属性中的user中的emp,在数据库中也就是t_user中的empid 查找本员工的用户是用本员工的id去用户中查找引用外键员工id 如果不设置property-ref="emp",找用户就会用自己的id去关联用户的id查找用户, 而不是用自己的id去关联用户中外键员工id查找用户 --> <one-to-one name="user" property-ref="emp" cascade="all" /> </class>
2) User.hbm.xml
<class name="User" table="T_USER"> <!-- 不使用员工的主键id了 --> <id name="id"> <generator class="increment" /> </id> <property name="username" /> <property name="password" /> <!-- 多个用户对应一个员工,配置一个员工外键, 但是唯一外键约束,也就相当于一个用户对应一个员工了 --> <many-to-one name="emp" column="empId" unique="true" cascade="all" /> </class>
3) 测试跟一对一共享主键关联一样
多对多关联
a) 多对多单双向关联
1) Student.java
private int id; private String name; // 加了teachers就是双向关联 private Set<Teacher> teachers = new HashSet<Teacher>(); //各种set、get方法 …… //hashCode和equals方法 ……
2) Student.hbm.xml
<class name="Student" table="t_student"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- 加了teachers就是双向关联 --> <set name="teachers" table="t_teacher_student" cascade="all" lazy="false" inverse="true"> <key column="studentId" /> <many-to-many class="Teacher" column="teacherId" /> </set> </class>
3) Teacher.java
private int id; private String name; private Set<Student> students = new HashSet<Student>(); //各种set、get方法 …… //hashCode和equals方法 ……
4) Teacher.hbm.xml
<class name="Teacher" table="t_teacher"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <set name="students" table="t_teacher_student" lazy="false" cascade="all"> <key column="teacherId" /> <many-to-many class="Student" column="studentId" /> </set> </class>
5) 测试多对多单双向关联
private Session session = null; private Transaction trans = null; /** * 多对多单向关联 */ @Test public void testAdd() { Student s1 = new Student(); s1.setName("张三同学"); Student s2 = new Student(); s2.setName("李四同学"); Student s3 = new Student(); s3.setName("王二同学"); Student s4 = new Student(); s4.setName("赵六同学"); Teacher t1 = new Teacher(); t1.setName("王老师"); Teacher t2 = new Teacher(); t2.setName("李老师"); t1.getStudents().add(s1); t1.getStudents().add(s2); t1.getStudents().add(s3); t2.getStudents().add(s1); t2.getStudents().add(s3); t2.getStudents().add(s4); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 由哪一端维护数据就由哪一端加对方,级联时就保存哪一端 session.save(t1); session.save(t2); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 多对多双向关联 */ @Test public void testAdd2() { Student s1 = new Student(); s1.setName("张三同学"); Student s2 = new Student(); s2.setName("李四同学"); Student s3 = new Student(); s3.setName("王二同学"); Student s4 = new Student(); s4.setName("赵六同学"); Teacher t1 = new Teacher(); t1.setName("王老师"); Teacher t2 = new Teacher(); t2.setName("李老师"); t1.getStudents().add(s1); t1.getStudents().add(s2); t1.getStudents().add(s3); s1.getTeachers().add(t1); s2.getTeachers().add(t1); s3.getTeachers().add(t1); t2.getStudents().add(s1); t2.getStudents().add(s3); t2.getStudents().add(s4); s1.getTeachers().add(t2); s3.getTeachers().add(t2); s4.getTeachers().add(t2); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 双方都维护数据时报错,因为共同维护数据就会插入一次相同的数据,因为关系表不能重复所以存在争议 // 所以需要一端放弃维护数据,此列学生端放弃维护数据 session.save(t1); session.save(t2); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
6) 多对多双向关联重建
private Session session = null; private Transaction trans = null; /** * 多对多双向关联关联重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Teacher t1 = (Teacher) session.get(Teacher.class, 1); System.out.println(t1.getName() + "的学生有:"); for (Student s : t1.getStudents()) { System.out.println(" " + s.getName()); } Teacher t2 = (Teacher) session.get(Teacher.class, 2); System.out.println(t2.getName() + "的学生有:"); for (Student s : t2.getStudents()) { System.out.println(" " + s.getName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 改良后的两个一对多替代多对多关联
1) StudentTeacher.java
private int id; private Student student; private Teacher teacher; private Date startTime; //各种set、get方法 …… //hashCode和equals方法 ……
2) StudentTeacher.hbm.xml
<class name="StudentTeacher" table="t_student_teacher"> <id name="id"> <generator class="increment" /> </id> <many-to-one name="student" column="studentId" cascade="all" /> <many-to-one name="teacher" column="teacherId" cascade="all" /> <property name="startTime" /> </class>
3) Student.java
private int id; private String name; private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>(); //各种set、get方法 …… //hashCode和equals方法 ……
4) Student.hbm.xml
<class name="Student" table="t_student"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <set name="studentTeachers" cascade="all" inverse="true"> <key column="studentId" /> <one-to-many class="StudentTeacher" /> </set> </class>
5) Teacher.java
private int id; private String name; private Set<StudentTeacher> studentTeachers = new HashSet<StudentTeacher>(); HashSet<StudentTeacher>(); //各种set、get方法 …… //hashCode和equals方法 ……
6) Teacher.hbm.xml
<class name="Teacher" table="t_teacher"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <set name="studentTeachers" cascade="all" inverse="true"> <key column="teacherId" /> <one-to-many class="StudentTeacher" /> </set> </class>
7) 测试改良的多对多
private Session session = null; private Transaction trans = null; /** * 改良的多对多关联(两个一对多,一个学生对应多个老师,一个老师对应多个学生,) */ @Test public void testAdd2() { Student s1 = new Student(); s1.setName("张三同学"); Student s2 = new Student(); s2.setName("李四同学"); Student s3 = new Student(); s3.setName("王二同学"); Student s4 = new Student(); s4.setName("赵六同学"); StudentTeacher st1 = new StudentTeacher(); StudentTeacher st2 = new StudentTeacher(); StudentTeacher st3 = new StudentTeacher(); Teacher t1 = new Teacher(); t1.setName("王老师"); st1.setStartTime(new Date()); st2.setStartTime(new Date()); st3.setStartTime(new Date()); st1.setTeacher(t1); st1.setStudent(s1); st2.setTeacher(t1); st2.setStudent(s2); st3.setTeacher(t1); st3.setStudent(s3); t1.getStudentTeachers().add(st1); t1.getStudentTeachers().add(st2); t1.getStudentTeachers().add(st3); // s3.getStudentTeachers().add(st1); StudentTeacher st4 = new StudentTeacher(); StudentTeacher st5 = new StudentTeacher(); StudentTeacher st6 = new StudentTeacher(); Teacher t2 = new Teacher(); t2.setName("李老师"); st4.setStartTime(new Date()); st5.setStartTime(new Date()); st6.setStartTime(new Date()); st4.setTeacher(t2); st4.setStudent(s2); st5.setTeacher(t2); st5.setStudent(s3); st6.setTeacher(t2); st6.setStudent(s4); t2.getStudentTeachers().add(st4); t2.getStudentTeachers().add(st5); t2.getStudentTeachers().add(st6); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(t1); session.save(t2); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
8) 改良的多对多重建
private Session session = null; private Transaction trans = null; /** * 改良的多对多双向关联关联重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Teacher t1 = (Teacher) session.get(Teacher.class, 1); System.out.println(t1.getName() + "的学生有:"); for (StudentTeacher st : t1.getStudentTeachers()) { System.out.println(" " + st.getStudent().getName()); } Student s2 = (Student) session.get(Student.class, 2); System.out.println(s2.getName() + "的老师有:"); for (StudentTeacher st : s2.getStudentTeachers()) { System.out.println(" " + st.getTeacher().getName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
组合映射
a) Contact.java
private String tel; private String phone; private String qq; private String email; @Override public String toString() { return "Contact [tel=" + tel + ", phone=" + phone + ", qq=" + qq + ", email=" + email + "]"; } //各种set、get方法 b) Address.java private String busiAddress; private String homeAddress; private Contact contact; @Override public String toString() { return "Address [busiAddress=" + busiAddress + ", homeAddress=" + homeAddress + ", contact=" + contact + "]"; } //各种set、get方法 User.java private int id; private String username; private String password; private Address address; @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + ", address=" + address + "]"; } //各种set、get方法
c) User.hbm.xml
<class name="User" table="T_USER"> <id name="id"> <generator class="increment" /> </id> <property name="username" /> <property name="password" /> <component name="address"> <property name="busiAddress" /> <property name="homeAddress" /> <component name="contact"> <property name="tel" /> <property name="phone" /> <property name="qq" /> <property name="email" /> </component> </component> </class> d) 测试组合映射 private Session session = null; private Transaction trans = null; /** * 测试组合映射 */ @Test public void testAdd() { User user = new User(); user.setUsername("zhaoliou"); user.setPassword("123456"); Address addr = new Address(); addr.setBusiAddress("北京"); addr.setHomeAddress("上海"); user.setAddress(addr); Contact con = new Contact(); con.setTel("458185544"); con.setPhone("18580505055"); con.setQq("992555181"); con.setEmail("etdd@kjdf.com"); addr.setContact(con); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(user); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试组合映射 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... User user = (User) session.get(User.class, 1); System.out.println(user.toString()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
继承映射
a) 继承映射(单表继承)
1) Substance.java
public interface Substance { }
2) Person.java
public class Person implements Substance { private int id; private String name; //各种set、get方法 …… }
3) Person.hbm.xml
<class name="Person" table="t_person"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> </class>
4) Animal.java
public class Animal implements Substance { private int id; private String name; //各种set、get方法 …… }
5) Dog.java
public class Dog extends Animal implements Substance { private double speed; //各种set、get方法 …… }
6) Pig.java
public class Pig extends Animal implements Substance { private double weight; //各种set、get方法 …… }
7) Extends.hbm.xml
<class name="Animal" table="t_animal"> <id name="id"> <generator class="increment" /> </id> <!-- discriminator:标识列,类型可以是int --> <discriminator column="discriminator" type="string" /> <property name="name" /> <!-- 建一张表有冗余,但性能最好 discriminator-value="D":以好分辨子类 --> <subclass name="Dog" discriminator-value="D"> <property name="speed" /> </subclass> <subclass name="Pig" discriminator-value="P"> <property name="weight" /> </subclass> </class>
8) 测试继承映射
i. 添加及重建
private Session session = null; private Transaction trans = null; /** * 测试继承映射 */ @Test public void testAdd() { Pig p = new Pig(); p.setName("大白猪"); p.setWeight(350.6); Dog d = new Dog(); d.setName("哈巴狗"); d.setSpeed(12.3); Person per = new Person(); per.setName("张三"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(d); session.save(p); session.save(per); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试继承映射的重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 多态查询 Animal a = (Animal) session.get(Animal.class, 1); Dog d = (Dog) a; System.out.println(d.getName() + ",速度:" + d.getSpeed()); Animal a2 = (Pig) session.get(Pig.class, 2); Pig p = (Pig) a2; System.out.println(p.getName() + ",体重:" + p.getWeight()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
ii. 继承映射中的问题(load方法无法实现多态查询)
private Session session = null; private Transaction trans = null; /** * 测试继承映射——懒加载 */ @Test public void testLoadQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 懒加载无法执行多态查询,Animal的代理子类无法转换成Dog类型 // Animal a = (Animal) session.load(Animal.class, 1); // Dog d = (Dog) a; // System.out.println(d.getName() + ",速度:" + d.getSpeed()); // 这个可以 // Animal a2 = (Pig) session.load(Pig.class, 2); Animal a2 = (Animal) session.load(Pig.class, 2); Pig p = (Pig) a2; System.out.println(p.getName() + ",体重:" + p.getWeight()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
iii. 基于接口及对象的隐式多态查询
private Session session = null; private Transaction trans = null; /** * 基于接口的隐式多态查询 */ @Test public void testSubstanceQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... String hql = "from com.alyshen.hibernate.domain.Substance"; Query query = session.createQuery(hql); List<Object> list = query.list(); for (Object o : list) { if (o instanceof Dog) { Dog d = (Dog) o; System.out.println(d.getName() + ",速度:" + d.getSpeed()); } if (o instanceof Pig) { Pig p = (Pig) o; System.out.println(p.getName() + ",体重:" + p.getWeight()); } if (o instanceof Person) { Person person = (Person) o; System.out.println(person.getName()); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 基于Object的隐式多态查询(接口都省了) */ @Test public void testObjectQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... String hql = "from java.lang.Object"; Query query = session.createQuery(hql); List<Object> list = query.list(); for (Object o : list) { if (o instanceof Dog) { Dog d = (Dog) o; System.out.println(d.getName() + ",速度:" + d.getSpeed()); } if (o instanceof Pig) { Pig p = (Pig) o; System.out.println(p.getName() + ",体重:" + p.getWeight()); } if (o instanceof Person) { Person person = (Person) o; System.out.println(person.getName()); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
iv. 基于父类的隐式多态查询(子类各一张表)
Animal.hbm.xml
<class name="Animal" table="t_animal"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> </class>
Dog.hbm.xml
<class name="Dog" table="t_dog"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <property name="speed" /> </class>
Pig.hbm.xml
<class name="Pig" table="t_pig"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <property name="weight" /> </class>
测试基于父类的隐式多态查询(子类各一张表)
private Session session = null; private Transaction trans = null; /** * 基于父类的隐式多态查询(接口都省了) */ @Test public void testAnimalQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... String hql = "from Animal"; Query query = session.createQuery(hql); List<Object> list = query.list(); for (Object o : list) { if (o instanceof Dog) { Dog d = (Dog) o; System.out.println(d.getName() + ",速度:" + d.getSpeed()); } if (o instanceof Pig) { Pig p = (Pig) o; System.out.println(p.getName() + ",体重:" + p.getWeight()); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试继承映射 */ @Test public void testAdd() { Pig p = new Pig(); p.setName("大白猪"); p.setWeight(350.6); Dog d = new Dog(); d.setName("哈巴狗"); d.setSpeed(12.3); Person per = new Person(); per.setName("张三"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(d); session.save(p); session.save(per); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 继承映射(每个子类一张表)
1) Extends.hbm.xml
<class name="Animal" table="t_animal"> <id name="id"> <generator class="increment" /> </id> <property name="name" /> <!-- 每个子类一张表 --> <joined-subclass name="Dog" table="t_dog"> <key column="aid" /> <property name="speed" /> </joined-subclass> <joined-subclass name="Pig" table="t_pig"> <key column="aid" /> <property name="weight" /> </joined-subclass> </class>
2) 测试跟单表继承一样
c) 继承映射(每个具体类一张表)
1) Extends.hbm.xml
<!-- 如果Animal不是抽象类,Animal也会生成一个表 --> <class name="Animal" table="t_animal"> <id name="id"> <!-- 数据库生成主键不可用 ,hibernate生成主键会判断主键id多少了, 因为继承需要多态查询,继承树中类的表主键id不能重复, 如果是数据库生成,它就不管别的表的主键id了 --> <generator class="increment" /> </id> <property name="name" /> <!-- 每个具体类一张表 --> <union-subclass name="Dog" table="t_dog"> <!-- 每个具体类一张表就不需要外键了 --> <property name="speed" /> </union-subclass> <union-subclass name="Pig" table="t_pig"> <property name="weight" /> </union-subclass> </class>
2) 测试跟单表继承一样
集合映射(Set集合)
a) 集合映射(Set集合)
1) Contact.java
private String tel; private String phone; private String qq; private String email; // 如果不重写equals和hashCode,对象就会默认根据地址对比对象,从数据库中查出来的地址根本就不同 // 对象不同时就会更新持久化对象到数据库,而集合映射出来的表更新操作就是删除然后添加 //equals、hashCode、各种set和get方法 ……
2) Address.java
private String busiAddress; private String homeAddress; private Contact contact; //equals、hashCode、各种set和get方法 ……
3) Person.java
private int id; private String name; private Set<String> photos = new HashSet<String>(); private Set<Address> addresses = new HashSet<Address>(); //各种set和get方法 ……
4) Person.hbm.xml
<class name="Person" table="t_person"> <id name="id"> <generator class="increment" /> </id> <property name="name" />
<composite-element class="Address"> <property name="busiAddress" /> <property name="homeAddress" /> <!-- 内嵌组合映射 --> <nested-composite-element name="contact" class="Contact"> <property name="tel" /> <property name="phone" /> <property name="qq" /> <property name="email" /> </nested-composite-element> </composite-element>
</class>
5) 测试集合Set映射
private Session session = null;
private Transaction trans = null;
/**
测试集合Set映射添加
*/
@Test
public void testAdd() {Person person = new Person();
person.setName("张三");
person.getPhotos().add("1.jpg");
person.getPhotos().add("2.jpg");
person.getPhotos().add("3.jpg");Contact c1 = new Contact();
c1.setTel("5685005");
c1.setPhone("1986556554");
c1.setQq("65485454");
c1.setEmail("dfkjd@kdjf.com");
Address addr1 = new Address();
addr1.setContact(c1);
addr1.setBusiAddress("北京");
addr1.setHomeAddress("天津");
person.getAddresses().add(addr1);Contact c2 = new Contact();
c2.setTel("545444544");
c2.setPhone("1634545454585");
c2.setQq("85454512");
c2.setEmail("yyy@163.com");Address addr2 = new Address();
addr2.setContact(c2);
addr2.setBusiAddress("上海");
addr2.setHomeAddress("南京");
person.getAddresses().add(addr2);try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....session.save(person); trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**
测试集合Set映射重建
*/
@Test
public void testQuery() {try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....Person person = (Person) session.get(Person.class, 1); System.out.println(person.getName()); for (String photo : person.getPhotos()) { System.out.println(photo); } for (Address a : person.getAddresses()) { System.out.println(a.getBusiAddress()); System.out.println(a.getHomeAddress()); System.out.println(a.getContact().getTel()); System.out.println(a.getContact().getPhone()); System.out.println(a.getContact().getQq()); System.out.println(a.getContact().getEmail()); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
b) 查询composite-element Set集合多发delete及insert语句的原因和解决方法
重写set集合中的对象的equals方法和hashCode方法
如果不重写equals和hashCode,对象就会默认根据地址对比对象,从数据库中查出来的地址根本就不同
对象不同时就会更新持久化对象到数据库,而集合映射出来的表更新操作就是删除然后添加
c) 集合映射(List集合)
1) Thing.java
private int id;
private String name;
//各种set、get方法
2) Thing.hbm.xml
3) Person.java
private int id;
private String name;
private List
private List
//各种set、get方法
4) Person.hbm.xml
<!-- list集合映射 记住:list集合映射不能放弃维护数据,否则将没有主键和索引 --> <list name="menu" table="t_menu"> <key column="personId" /> <list-index column="list_index" /> <element column="menuOrder" type="string" /> </list> <list name="things" cascade="all"> <key column="personId" /> <list-index column="list_index" /> <one-to-many class="Thing" /> </list> </class>
5) 测试集合List映射
private Session session = null;
private Transaction trans = null;
/** * 测试集合List映射添加 */ @Test public void testAdd() { Person person = new Person(); person.setName("张三"); Thing t1 = new Thing(); t1.setName("吃的"); Thing t2 = new Thing(); t2.setName("喝的"); person.getMenu().add("加油"); person.getMenu().add("加鸡蛋"); person.getMenu().add("加盐"); person.getMenu().add("加油"); person.getMenu().add("加青菜"); person.getMenu().add("加盐"); person.getThings().add(t1); person.getThings().add(t2); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试集合List映射重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Person person = (Person) session.get(Person.class, 1); System.out.println(person.getName()); for (String menu : person.getMenu()) { System.out.println(menu); } for (Thing t : person.getThings()) { System.out.println(t.getName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
d) 集合映射(Map集合)
1) Person.java
private int id;
private String name;
private Map<String, String> images = new HashMap<String, String>();
//各种set、get方法
……
2) Person.hbm.xml
<!-- map集合映射 --> <map name="images" table="t_image"> <key column="personId" /> <map-key column="map_key" type="string" /> <!-- 如果是对象,用 <composite-element class=""> --> <element column="imageName" type="string" /> </map> </class>
3) 测试集合Map映射
private Session session = null;
private Transaction trans = null;
/** * 测试集合Map映射添加 */ @Test public void testAdd() { Person person = new Person(); person.setName("张三"); person.getImages().put("img1", "c:/image/1.jpg"); person.getImages().put("img2", "c:/image/2.jpg"); person.getImages().put("img3", "c:/image/3.jpg"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... session.save(person); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } /** * 测试集合Map映射重建 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Person person = (Person) session.get(Person.class, 1); System.out.println(person.getName()); System.out.println(person.getImages().get("img1")); /** * 将map集合中所有元素的键放在一个set集合中, * 然后遍历这个set集合根据每个键去取值 */ Set<String> keys = person.getImages().keySet(); for (String key : keys) { System.out.println(person.getImages().get(key)); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
I. HQL(Hibernate Query Language)
HQL查询基本规则及查询方法
private Session session = null; private Transaction trans = null; /** * hql查询 */ @Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // String hql = "FROM com.alyshen.hibernate.domain.User";// 标准hql // String hql = "FROM User";// 如果User在整个项目是唯一的 // String hql = "FROM User AS u";// 设置别名 // String hql = "FROM User u";// 设置别名 String hql = "Select u FROM User u";// 设置别名,加select Query query = session.createQuery(hql); List<User> list = query.list(); for (User u : list) { System.out.println(u.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
HQL条件参数查询
a) 硬编码
private Session session = null; private Transaction trans = null; /** * hql参数查询(硬编码) */ @Test public void testQuery() { int max = 23; int min = 10; String param = "'%2%'"; try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // String hql = "Select u FROM User u WHERE u.id > 10 AND u.id < 23"; // String hql = "Select u FROM User u WHERE u.id BETWEEN 10 AND 23"; // BETWEEN:在……之间(包含数字) String hql = "Select u FROM User u WHERE u.id BETWEEN " + min + " AND " + max + " AND u.username like " + param; Query query = session.createQuery(hql); List<User> list = query.list(); for (User u : list) { System.out.println(u.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) 匿名参数
private Session session = null;
private Transaction trans = null;
/**
* hql参数查询(参数查询:匿名参数)
*/
@Test
public void testQuery2() {
int max = 23; int min = 10; String param = "%2%";// 不需要单引号''了 try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... String hql = "Select u FROM User u WHERE u.id BETWEEN ? AND ? AND u.username like ?"; Query query = session.createQuery(hql); query.setParameter(0, min); query.setParameter(1, max); query.setParameter(2, param); List<User> list = query.list(); for (User u : list) { System.out.println(u.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } } c) 命名参数 private Session session = null; private Transaction trans = null; /** * hql参数查询(参数查询:命名参数) */ @Test public void testQuery3() { int max = 23; int min = 10; String param = "%2%";// 不需要单引号''了 try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... String hql = "Select u FROM User u WHERE u.id BETWEEN :min AND :max AND u.username like :param"; Query query = session.createQuery(hql); query.setParameter("min", min); query.setParameter("max", max); query.setParameter("param", param); List<User> list = query.list(); for (User u : list) { System.out.println(u.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
HQL集合类型的参数查询
private Session session = null;
private Transaction trans = null;
/**
hql集合参数查询(命名参数)
*/
@Test
public void testQuery() {try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// String hql = "Select u FROM User u WHERE u.id IN(1,2,3,4,5,6,7)";
String hql = "Select u FROM User u WHERE u.id IN(:ids)";List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); ids.add(3); ids.add(4); ids.add(5); ids.add(6); ids.add(7); Query query = session.createQuery(hql); /** * 不能使用普通的设置参数方法 */ query.setParameterList("ids", ids); List<User> list = query.list(); for (User u : list) { System.out.println(u.getId() + ":" + u.getUsername()); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
HQL空值判断及处理
private Session session = null;
private Transaction trans = null;
/**
hql空值判断
*/
@Test
public void testQuery() {try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// String hql = "Select u FROM User u WHERE u.username=NULL";
// =NULL:Hibernate容错处理,不建议
// String hql = "Select u FROM User u WHERE u.username IS NULL";
// String hql = "Select u FROM User u WHERE u.group.id IS NULL";
String hql = "Select u FROM User u WHERE u.group IS NULL";
Query query = session.createQuery(hql); List<User> list = query.list(); for (User u : list) { System.out.println(u.getId() + ":" + u.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
HQL聚合函数及uniqueResult方法
private Session session = null;
private Transaction trans = null;
/**
hql聚合函数及uniqueResult()
*/
@Test
public void testQuery() {try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....String hql = "Select COUNT(*) FROM User"; Query query = session.createQuery(hql); // List<Integer> list = query.list(); // System.out.println(list.get(0)); //当确定只有一条记录时用uniqueResult方法 Long c = (Long) query.uniqueResult(); System.out.println(c); hql = "SELECT u FROM User u WHERE u.id = 115"; query = session.createQuery(hql); User u = (User) query.uniqueResult(); System.out.println(u); System.out.println(u.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL分组聚合及having子句
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
/**
* hql分组聚合函数
/
// 使用投影,返回对象集合(包含u.group.groupName,COUNT()的对象数组)
String hql = "Select u.group.groupName,COUNT(*) FROM User u GROUP BY u.group";
Query query = session.createQuery(hql);
// 一个字段包装成一个对象,一行字段包装成一个对象数组, //将每行字段包装成的每个对象数组放入到list集合中 List<Object[]> objss = query.list(); for (Object[] objs : objss) { System.out.println(objs[0] + ":" + objs[1]); } /** * hql分组聚合条件 */ // 使用投影,返回对象数组(包含u.group.groupName,COUNT(*)的对象数组) // 聚合过的数据只能用HAVING,不能用WHERE hql = "Select u.group.groupName,COUNT(*) FROM User u Group BY u.group HAVING COUNT(*)<90"; query = session.createQuery(hql); // 一个字段包装成一个对象,一行字段包装成一个对象数组, //将每行字段包装成的每个对象数组放入到list集合中 objss = query.list(); for (Object[] objs : objss) { System.out.println(objs[0] + ":" + objs[1]); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
/**
添加测试数据
*/
@Test
public void testAdd() {Group g1 = new Group();
g1.setGroupName("一组");
Group g2 = new Group();
g2.setGroupName("二组");
Group g3 = new Group();
g3.setGroupName("三组");
Group g4 = new Group();
g4.setGroupName("四组");
Group g5 = new Group();
g5.setGroupName("五组");try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
for (int i = 0; i < 500; i++) {
User user = new User();
user.setUsername("用户_" + new Random().nextInt(9999));
user.setPassword("密码_" + new Random().nextInt(9999));
if (i <= 50) {
user.setGroup(g1);
} else if (i <= 120) {
user.setGroup(g2);
} else if (i <= 200) {
user.setGroup(g3);
} else if (i < 300) {
user.setGroup(g4);
} else {
user.setGroup(g5);
}
session.save(user);
}
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
HQL投影查询
a) 投影查询
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
String hql = "Select u.id FROM User u"; Query query = session.createQuery(hql); List<Integer> ids = query.list(); for (Integer id : ids) { System.out.println(id); } hql = "Select u.username FROM User u"; query = session.createQuery(hql); List<String> names = query.list(); for (String username : names) { System.out.println(username); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
b) 投影查询(多列)
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery2() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
String hql = "Select u.username,u.password FROM User u"; Query query = session.createQuery(hql); // 一个字段包装成一个对象,一行字段包装成一个对象数组, //将每行字段包装成的每个对象数组放入到list集合中 List<Object[]> objss = query.list(); for (Object[] objs : objss) { for (Object obj : objs) { System.out.print(obj); } System.out.println(); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
c) 对象化投影查询(多列)
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery3() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// User类要有这个构造方法 String hql = "Select new User(u.username,u.password) FROM User u"; Query query = session.createQuery(hql); // 返回你有查询出的字段,每一行字段包装成一个对象数组,多行就是一个list集合的对象数组 List<User> users = query.list(); for (User user : users) { System.out.println(user.getUsername() + ":" + user.getPassword()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
HQL中的单行函数
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// 绝对值:ABS(n)、开方:SQRT(n)、除法:MOD(dividend,divisor)
hql =
// 转大写,转小写
// "SELECT UPPER(u.username),LOWER(u.password) FROM User u";
//合并字符串:CONCAT(s1,s2); //update t_user set username=CONCAT(username,'siJHKjkWSdxHJIOMhKJk'),passwo
// rd=CONCAT(password,'OyrBMDcswXZgKOAq');
// 截取,参数:要截取的字符串,位置,长度 // "SELECT SUBSTRING(u.username,2,3),LOWER(u.password) FROM User u"; // 求长度 // "SELECT LENGTH(u.username),LOWER(u.password) FROM User u"; // 求位置 // "SELECT LOCATE('户',u.username),LOWER(u.password) FROM User u"; // 求字节数 // "SELECT BIT_LENGTH(u.username),LOWER(u.password) FROM User u"; // "SELECT BIT_LENGTH(20),LOWER(u.password) FROM User u"; // 日期:CURRENT_DATE()、时间:CURRENT_TIME()、时间戳:CURRENT_TIMESTAMP()、 // "SELECT CURRENT_DATE(),CURRENT_TIMESTAMP() FROM User u"; // 得到时间的某一类型的值,SECOND(d)、分:MINUTE(d)、时:HOUR(d)、天:DAY(d)、月:MOUTH(d)、年:YEAR(d)、Date(d)、 // "SELECT DAY(CURRENT_DATE()),LOWER(u.password) FROM User u"; // 类型转换 // "SELECT CAST('2015-2-8' AS date),LOWER(u.password) FROM User u"; "SELECT CAST('25455' AS int),LOWER(u.password) FROM User u"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println((Integer) os[0] + ":" + os[1]); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL分页查询和排序
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// 查询所有用户并降序 hql = "SELECT u FROM User u ORDER BY u.id DESC"; Query query = session.createQuery(hql); // 分页参数 query.setFirstResult(32);//从32条开始 query.setMaxResults(10); List<User> users = query.list(); for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL隐式连接
/**
hql隐式内链1
*/
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// 查询所有用户包括组的一些字段 hql = "SELECT u.id,u.username,u.group.id,u.group.groupName FROM User u"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1] + "," + os[2] + ":" + os[3]); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**
hql隐式内链(交叉连接)
*/
@Test
public void testQuery2() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// 查询所有用户包括组的一些字段(使用cross join交叉连接,耗资源,不建议使用) hql = "SELECT u.id,u.username FROM User u WHERE u.group.groupName LIKE '%二%'"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1]); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
HQL显式内连接
private Session session = null;
private Transaction trans = null;
/**
hql显式内链(尽量用显示的,因为容易控制)
*/
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// 这使用的还是交叉连接:cross join // "SELECT u.id,u.username,g.id,g.groupName FROM User u,Group g"; // 使用的内链接:inner join // "SELECT u.id,u.username,g.id,g.groupName FROM User u JOIN u.group g"; // 加参数 hql = "SELECT u.id,u.username,g.id,g.groupName FROM User u JOIN u.group g WHERE g.groupName LIKE '%二%'"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1] + "," + os[2] + ":" + os[3]); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
HQL左右外连接
a) 添加测试数据
private Session session = null;
private Transaction trans = null;
@Test
public void testAdd() {
Group g1 = new Group(); g1.setGroupName("一组"); Group g2 = new Group(); g2.setGroupName("二组"); Group g3 = new Group(); g3.setGroupName("三组"); Group g4 = new Group(); g4.setGroupName("四组"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... for (int i = 0; i < 200; i++) { User user = new User(); user.setUsername("用户_" + new Random().nextInt(9999)); user.setPassword("密码_" + new Random().nextInt(9999)); if (i <= 50) { user.setGroup(g1); } else if (i <= 80) { user.setGroup(g2); } else if (i <= 120) { user.setGroup(g3); } else if (i < 160) { user.setGroup(g4); } session.save(user); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
b) 显式左外链
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// 左边的全部查出来:left outer join hql = "SELECT u.id,u.username,g.groupName FROM User u LEFT JOIN u.group g"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1] + "," + os[2]); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
c) 显式右外链
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery2() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// 右边的全部查出来:right outer join hql = "SELECT u.id,u.username,g.groupName FROM Group g RIGHT JOIN g.users u"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1] + "," + os[2]); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL不相关子查询及相关子查询
a) 添加测试数据
private Session session = null;
private Transaction trans = null;
@Test
public void testAdd() {
Group g1 = new Group(); g1.setGroupName("一组"); Group g2 = new Group(); g2.setGroupName("二组"); Group g3 = new Group(); g3.setGroupName("三组"); Group g4 = new Group(); g4.setGroupName("四组"); Group g5 = new Group(); g5.setGroupName("五组"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... for (int i = 0; i < 200; i++) { User user = new User(); user.setUsername("用户_" + new Random().nextInt(9999)); user.setPassword("密码_" + new Random().nextInt(9999)); if (i <= 50) { user.setGroup(g1); } else if (i <= 80) { user.setGroup(g2); } else if (i <= 120) { user.setGroup(g3); } else if (i < 160) { user.setGroup(g4); } session.save(user); } session.save(g5); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
b) 不相关子查询
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// // 未分组的用户 // hql = // "SELECT u.id,u.username FROM User u WHERE u.group.id IS NULL"; // 用户id是组id的用户 //子查询中没有引用查询中的引用就是不相关子查询 hql = "SELECT u.id,u.username FROM User u WHERE u.id IN( SELECT g.id FROM Group g)"; Query query = session.createQuery(hql); List<Object[]> objs = query.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1]); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
c) 相关子查询
private Session session = null;
private Transaction trans = null;
@Test
public void testQuery2() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// 查询组中用户数大于35的组 // 在(SELECT COUNT(*) FROM g.users) 中引用g,叫相关子查询 // 在子查询中引用查询中的别名就是相关子查询 hql = "SELECT g FROM Group g WHERE(SELECT COUNT(*) FROM g.users) > 35"; Query query = session.createQuery(hql); List<Group> groups = query.list(); for (Group group : groups) { System.out.println(group.getId() + ":" + group.getGroupName()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL外置命名查询
a) User.hbm.xml
……
<[CDATA[
SELECT u FROM User u WHERE u.id < ?
]]>
b) 测试外置命名查询
@Test
public void testSearchUser() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// hql = "SELECT u FROM User u WHERE u.id < ?"; // Query query = session.createQuery(hql); // Query query = session.getNamedQuery("searchUser"); // query.setParameter(0, 20); // List<User> users = query.list(); // 这样也行 List<User> users = session.getNamedQuery("searchUser") .setParameter(0, 20).list(); for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
HQL过滤器的作用及用法
a) 定义过滤器
1) Filter.hbm.xml
b) 使用过滤器
1) User.hbm.xml
<id name="id" column="_id"> <generator class="increment" /> </id> <property name="username" /> <property name="password" /> <many-to-one name="group" column="groupId" cascade="all" /> <!-- 此时设置的_id是表字段中的_id,不是实体的id,它会添加到SQL语句后面,而不是HQL语句后面 --> <filter name="queryFilter" condition="_id < :condition" />
2) 使用过滤器查数据
private Session session = null;
private Transaction trans = null;
/**
HQL过滤器
*/
@Test
public void testFilterQuery() {
String hql = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// 使用过滤器 session.enableFilter("queryFilter").setParameter("condition", 20); hql = "SELECT u FROM User u"; List<User> users = session.createQuery(hql).list(); for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
J. 标准化对象查询(Critria)
Critria的QBC查询
a) QBC设置条件的一些方法
b) 测试QBC查询
private Session session = null;
private Transaction trans = null;
@Test
public void testCriteriaQuery() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
Criteria criteria = session.createCriteria(User.class); criteria // 用户名包含字符串“2”的 .add(Restrictions.like("username", "%2%")) // 用户id小于150的 .add(Restrictions.lt("id", 150)) // 排序:id降序 .addOrder(Order.desc("id")) // Order.asc("id")) // 创建查询,使用的内链: inner join .createCriteria("group") // 组名包含“二”的 .add(Restrictions.like("groupName", "%二%")) // 第2条开始(参数包括0) .setFirstResult(2) // 最大条数 .setMaxResults(10); List<User> users = criteria.list(); for (User user : users) { System.out.print(user.toString()); if (user.getGroup() != null) { System.out.println(user.getGroup().toString()); } else { System.out.println(); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
Critria的QBE查询
/**
测试QBE查询
*/
@Test
public void testQuery2() {try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....User user = new User(); user.setUsername("2"); user.setPassword("1");
// // hql查询的问题:判断次数过多
// String hql = "select u from User u where 1=1";
// if (u.getUsername() != null) {
// hql += " and u.username like '%" + u.getUsername() + "%'";
// }
// if (u.getPassword() != null) {
// hql += " and u.password like '%" + u.getPassword() + "%'";
// }
// Query query = session.createQuery(hql);
// List
Criteria criteria = session.createCriteria(User.class); // 增加一个范例, criteria.add(Example.create(user) // 启用模糊查询 // MatchMode.ANYWHERE:什么时候都启用,MatchMode.START:将参数放前面,%放在后面 // MatchMode.EXACT:不放% .enableLike(MatchMode.ANYWHERE) // 去除某一个参数,password不参加模糊查询 .excludeProperty("password")); List<User> users = criteria.list(); for (User us : users) { System.out.print(us.toString()); if (us.getGroup() != null) { System.out.println(us.getGroup().toString()); } else { System.out.println(); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
Critria的投影查询
@Test
public void testQuery3() {
try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... Criteria criteria = session.createCriteria(User.class); /** * 投影查询(一个列) */ // criteria.setProjection(Projections.property("username")); // // List<String> usernames = criteria.list(); // for (String username : usernames) { // System.out.println(username); // } /** * 投影查询(多个列) */ // 定义投影查询的多个列 criteria.setProjection(Projections.projectionList() .add(Projections.property("username")) .add(Projections.property("password"))); List<Object[]> objs = criteria.list(); for (Object[] os : objs) { System.out.println(os[0] + ":" + os[1]); } /** * 统计查询 */ // 定义投影查询的列 criteria.setProjection(Projections.rowCount()); Long count = (Long) criteria.uniqueResult(); System.out.println("列数:" + count); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
K. 原生SQL查询(Native SQL Queries)
private Session session = null;
private Transaction trans = null;
@Test public void testQuery() { try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... /** * hibernate使用原生SQL查询出来的实体缓存不了, * 有些sql语句hibernate写不了,只能用本地sql */ // // String sql = "select * from t_user"; // // String sql = "select username,password from t_user"; // // SQLQuery sqlquery = session.createSQLQuery(sql); // List<Object[]> objs = sqlquery.list(); // for (Object[] os : objs) { // System.out.println(os[0] + ":" + os[1]); // } /** * 原生SQL查询(注册实体) */ String sql = "select * from t_user"; SQLQuery sqlquery = session.createSQLQuery(sql); // 将查询到的结果封装到指定的实体 sqlquery.addEntity(User.class); List<User> users = sqlquery.list(); for (User user : users) { System.out.println(user.toString()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
L. hibernate的缓存机制
- hibernate的缓存结构
内置缓存(不能取消,均由session管理,线程安全,不会有线程争论问题)一级缓存
session缓存储存:
普通属性
select u.id,u.username from User u
sessionFactory内置缓存储存:
实体对象(session关闭,实体销毁)
from User
外置缓存(可以配置,可以取消,容易出现线程安全的问题,
管理的时候,要注意隔离级别,数据库经常讲隔离级别,因为在hibernate二级缓存当中也会有幻象读)
二级缓存储存:
实体对象(共享,session关闭,实体还在,需要配置什么时候销毁,如果不配销毁时间,生
命周期应该跟这应用程序生命周期一样长)
from User
查询缓存储存:
普通属性
select u.id,u.username from User u
实体对象
存实体ID
二级缓存和查询缓存都可以跟session去交互
- 一级缓存
a) 测试一级缓存
private Session session = null;
private Transaction trans = null;
@Test
public void testOneLevelCache() {try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // .....
// // 测试get
// User user = (User) session.get(User.class, 1);
// System.out.println(user.getUsername());
//
// user = (User) session.get(User.class, 1);
// System.out.println(user.getUsername());
// // 再次查询没有发出sql语句说明是使用 缓存中的数据
// 测试load
// User user = (User) session.load(User.class, 1);
// System.out.println(user.getUsername());
//
// user = (User) session.load(User.class, 1);
// System.out.println(user.getUsername());
// // 再次查询没有发出sql语句说明是使用 缓存中的数据
// 测试list
List
User user = (User) session.load(User.class, 1); System.out.println(user.getUsername()); user = (User) session.load(User.class, 1); System.out.println(user.getUsername()); // 所有数据查出来了之后再次查询没有发出sql语句说明是使用 缓存中的数据 trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
b) session 关闭后该session所查出的数据也被销毁
private Session session = null;
private Transaction trans = null;
/**
* 一级缓存
* 测试session关闭后数据是否还存在缓存中
*/
@Test
public void testOneLevelCache2() {
try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... List<User> users = session.createQuery("FROM User").list(); User user = (User) session.load(User.class, 1); System.out.println(user.getUsername()); user = (User) session.get(User.class, 1); System.out.println(user.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... List<User> users = session.createQuery("FROM User").list(); // session 关闭之后数据也被销毁, //所以重新打开session查询同样的数据会重新发出一条sql语句去查数据 User user = (User) session.load(User.class, 1); System.out.println(user.getUsername()); user = (User) session.get(User.class, 1); System.out.println(user.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
c) 一级缓存对list方法及iterator方法的作用
private Session session = null;
private Transaction trans = null;
@Test
public void testCacheQuery() {
try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // .....
// // 测试list
// List
// for (User user : users) {
// System.out.println(user.getUsername());
// }
// // 这次查询时又发出了一条sql语句,说明没有使用缓存,
// //list方法只会把数据放到缓存中,不会从缓存中取数据
// users = session.createQuery("FROM User").list();
// for (User user : users) {
// System.out.println(user.getUsername());
// }
// // 测试iterate方法
// Iterator
// while (iter.hasNext()) {
// System.out.println(iter.next().getUsername());
// }
// // 这次只查id,说明从缓存中取数据了,但是第一次查询发出了n+1条sql语句,消耗资源
// iter = session.createQuery("FROM User").iterate();
// while (iter.hasNext()) {
// System.out.println(iter.next().getUsername());
// }
// 测试list方法和iterate方法的配合使用效率 List<User> users = session.createQuery("FROM User").list(); for (User user : users) { System.out.println(user.getUsername()); } // 这次只查id,说明iterate方法从缓存中取数据了, //利用list方法一次查询存入缓存,用iterate方法去缓存中提取,提高效率 Iterator<User> iter = session.createQuery("FROM User").iterate(); while (iter.hasNext()) { System.out.println(iter.next().getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- 二级缓存
a) 用到的包及文件
oscache-2.1.jar
commons-logging-1.1.3.jar
oscache.properties
b) 二级缓存的配置
hibernate.cfg.xml中配置:
<!-- 注册二级缓存提供商,这里是OS提供商 --> <property name="hibernate.cache.provider_class">org.hibernate.cache.OSCacheProvider</property> <!-- 配置使用二级缓存的类,一般到这里配置,更好管理,或者到实体类映射文件中配置 --> <class-cache usage="read-only" class="com.alyshen.hibernate.domain.Group" />
加载文件:
hibernate-distribution-3.6.1.Final\project\etc\oscache.properties
hibernate-distribution-3.6.1.Final\lib\optional\oscache\oscache-2.1.jar
struts-2.3.16.3\lib\commons-logging-1.1.3.jar
User.hbm.xml中配置:
c) 测试二级缓存
private Session session = null;
private Transaction trans = null;
@Test
public void testTwoCache() {
try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... List<User> users = session.createQuery("FROM User").list(); User user = (User) session.load(User.class, 2); System.out.println(user.getUsername()); System.out.println(user.getGroup().getGroupName()); user = (User) session.load(User.class, 7); System.out.println(user.getUsername()); user = (User) session.get(User.class, 9); System.out.println(user.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println("--------------关闭session后--------------------"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... User user = (User) session.load(User.class, 2); System.out.println(user.getUsername()); System.out.println(user.getGroup().getGroupName()); user = (User) session.load(User.class, 18); System.out.println(user.getUsername()); user = (User) session.get(User.class, 35); System.out.println(user.getUsername()); // session 关闭之后一级缓存中的数据被销毁,重新打开session时 //再查询同样的数据时不会重新发出一条sql语句去查询数据,说明使用了二级缓存中的数据 trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
d) 管理二级缓存
private Session session = null;
private Transaction trans = null;
@Test
public void testTwoCache2() {
try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... List<User> users = session.createQuery("FROM User").list(); User user = (User) session.load(User.class, 2); System.out.println(user.getUsername()); System.out.println(user.getGroup().getGroupName()); user = (User) session.load(User.class, 7); System.out.println(user.getUsername()); user = (User) session.get(User.class, 9); System.out.println(user.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } System.out.println("--------------关闭session后--------------------"); try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... // 踢出指定的实体 // HibernateUtil.getFactory().getCache().evictEntity(User.class, 1); // 踢出所有的 // HibernateUtil.getFactory().getCache().evictEntityRegions(); // 踢出指定域 HibernateUtil.getFactory().getCache().evictEntityRegion(User.class); User user = (User) session.load(User.class, 2); System.out.println(user.getUsername()); System.out.println(user.getGroup().getGroupName()); user = (User) session.load(User.class, 1); System.out.println(user.getUsername()); user = (User) session.get(User.class, 35); System.out.println(user.getUsername()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } }
- 查询缓存
a) 查询缓存配置
二级缓存配置好了之后再在hibernate.cfg.xml中配置:true b) 使用查询缓存
private Session session = null;
private Transaction trans = null;
@Test
public void testQueryCache() {
Listusers = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// 启用查询缓存为true users = session.createQuery("FROM User").setCacheable(true).list(); for (User user : users) { System.out.println(user.getUsername()); } System.out.println("再次用query.list执行相同的查询-"); users = session.createQuery("FROM User").setCacheable(true).list(); for (User user : users) { System.out.println(user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... System.out.println("关闭session后,再次用query.list执行相同的查询"); users = session.createQuery("FROM User").setCacheable(true).list(); // 没有发出sql语句查询,越过session,说明使用了二级缓存中的数据 for (User user : users) { System.out.println(user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}c) 查询缓存的局限性
private Session session = null;
private Transaction trans = null
@Test
public void testQueryCache2() {
Listusers = null;
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....users = session.createQuery("FROM User u WHERE u.id > ?") .setParameter(0, 20).setCacheable(true).list(); for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } System.out.println("再次用query.list执行不同条件的查询"); users = session.createQuery("FROM User u WHERE u.id > ?") .setParameter(0, 25).setCacheable(true).list(); // 参数改变之后就会重新发出sql语句查询,说明查询的sql语句必须一致才会使用查询缓存 for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); } try { session = HibernateUtil.getSession(); trans = session.beginTransaction(); // ..... System.out.println("关闭session后,再次用query.list执行不同条件的查询"); users = session.createQuery("FROM User u WHERE u.id > ?") .setParameter(0, 30).setCacheable(true).list(); // 参数改变之后就会重新发出sql语句查询,说明查询的sql语句必须一致才会使用查询缓存 for (User user : users) { System.out.println(user.getId() + ":" + user.getUsername()); } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
## M. 查询关联实体抓取策略
- many2one的单端抓取策略
a) User.hbm.xml
b) 使用Many2One单向抓取策略
private Session session = null;
private Transaction trans = null;
@Test
public void testFetchStrategy() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// User user = (User) session.get(User.class, 2); // load()也可以 User user = (User) session.load(User.class, 2); // left outer join使用左外链接查询出组数据 System.out.println(user.getUsername()); System.out.println(user.getGroup().getGroupName()); trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
- many2one的批量抓取策略
a) Group.hbm.xml
……b) 使用Many2One批量抓取策略
private Session session = null;
private Transaction trans = null;
@Test
public void testFetchStrategy2() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....String hql = "FROM User"; List<User> users = session.createQuery(hql).list(); for (User user : users) { System.out.println(user.getUsername()); if (user.getGroup() != null) { // 内链查询所有的数据量太大,内链抓取策略失效,可以调节一次性被抓取指定实体的个数 System.out.println(user.getGroup().getGroupName()); } } trans.commit(); } catch (HibernateException e) { trans.rollback(); e.printStackTrace(); } finally { HibernateUtil.closeSession(session); }
}
- One2Many的单端和批量抓取策略
a) Group.hbm.xml
b) 使用One2Many的单端和批量抓取策略
private Session session = null;
private Transaction trans = null;
/**- One2Many单向抓取策略
*/
@Test
public void testFetchStrategy() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// Group group = (Group) session.get(Group.class, 2);
// load()也可以
Group group = (Group) session.load(Group.class, 2);
// left outer join
System.out.println(group.getGroupName());
for (User user : group.getUsers()) {
System.out.println(" " + user.getUsername());
}
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/** - One2Many批量抓取策略
*/
@Test
public void testFetchStrategy2() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
String hql = "FROM Group";
Listgroups = session.createQuery(hql).list();
for (Group group : groups) {
System.out.println(group.getGroupName());
for (User user : group.getUsers()) {
// 内链批量抓取策略失效
System.out.println(" " + user.getUsername());
}
}
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
} N. 并发访问问题
- One2Many单向抓取策略
- 并发访问的悲观锁策略
a) Account.java
private int id;
private String accountName;
private long money;
//各种set、get方法
…… b) Account.hbm.xmlc) 悲观锁测试
private Session session = null;
private Transaction trans = null;
/**张三卡里有5000元钱
*/
@Test
public void testAdd() {
Account account = new Account();
account.setAccountName("zhangsan");
account.setMoney(5000);
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
session.save(account);
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**张三来取钱
*/
@Test
public void testUpdate1() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....// LockMode.UPGRADE:锁模式,过期了,不使用了 // LockOptions.UPGRADE:锁设置 // 悲观锁 // Account account = (Account) session.get(Account.class, 1); Account account = (Account) session.get(Account.class, 1, LockOptions.UPGRADE); long money = account.getMoney(); // 取2000元 account.setMoney(money - 2000); // 在等待1分钟回显时,张三的媳妇也来取钱了 trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**
张三的媳妇也来取钱
*/
@Test
public void testUpdate2() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
// Account account = (Account) session.get(Account.class, 1);//加了锁之后:张三取钱时在等待1分钟回显时,这里就访问不了了 Account account = (Account) session.get(Account.class, 1, LockOptions.UPGRADE); long money = account.getMoney(); // 取2000元 account.setMoney(money - 2000); // 张三等待1分钟还没有回显,张三的媳妇就取完了,提交了 trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
- 并发访问的乐观锁策略
a) Account.java
private int id;
private String accountName;
private long money;
private int version;
//各种set、get方法
……b) Account.hbm.xml
<!-- 由hibernate维护,不需人为添加数据 --> <version name="version" /> <property name="accountName" /> <property name="money" />
c) 测试乐观锁
private Session session = null;
private Transaction trans = null;
/**张三卡里有5000元钱
*/
@Test
public void testAdd() {
Account account = new Account();
account.setAccountName("zhangsan");
account.setMoney(5000);try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....session.save(account); trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**张三来取钱
*/
@Test
public void testUpdate1() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
Account account = (Account) session.get(Account.class, 1);
long money = account.getMoney();
// 取2000元
account.setMoney(money - 2000);// 等待1分钟回显时,张三的媳妇也来取钱了 // 等着等着银行的人就告诉你取钱出现了异常… trans.commit();
} catch (HibernateException e) {
//更新时版本跟查出来的版本不一致,更新失败
//update t_account set version=?, accountName=?, money=? where id=? and version=?
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}
/**- 张三的媳妇也来取钱
*/
@Test
public void testUpdate2() {
try {
session = HibernateUtil.getSession();
trans = session.beginTransaction();
// .....
Account account = (Account) session.get(Account.class, 1);
long money = account.getMoney();
// 取2000元
account.setMoney(money - 2000);
// 张三等待1分钟还没回显,张三的媳妇就取完了,提交了
trans.commit();
} catch (HibernateException e) {
trans.rollback();
e.printStackTrace();
} finally {
HibernateUtil.closeSession(session);
}
}O. hibernate4
- hibernate4简介及环境配置
a) 需要的包
antlr-2.7.7.jar
dom4j-1.6.1.jar
hibernate-commons-annotations-4.0.2.Final.jar
hibernate-core-4.2.16.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
javassist-3.18.1-GA.jar
jboss-logging-3.1.0.GA.jar
jboss-transaction-api_1.1_spec-1.0.1.Final.jar 此包及以上都是核心包
log4j-1.2.17.jar 需要一个配置文件
mysql-connector-java-5.1.6-bin.jarb) hibernate.cfg.xml
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <property name="hibernate.show_sql">true</property> <!-- 格式化sql语句 <property name="hibernate.format_sql">true</property> --> <property name="hbm2ddl.auto">update</property> <!-- 配置currentSession的上下文环境 <property name="hibernate.current_session_context_class">jta</property> --> <property name="hibernate.current_session_context_class">thread</property> <!-- 映射类实体 --> <mapping class="com.alyshen.hibernate4.domain.User" /> </session-factory>
- hibernate4的第一个示例
a) User.java
Entity和Table注解、注解配置ID及生成策略、列定义注解配置
@Entity
@Table(
// 指定表名
name = "t_user"
// 指定数据库
,schema = "hibernate"
//// 唯一约束
//,uniqueConstraints = {
// @UniqueConstraint(columnNames = { "username" }),
// @UniqueConstraint(columnNames = { "password" }),
// }
)
public class User {private Integer id;
private String username;
private String password;
private Integer age;
private char sex;@Id
@Column(name="_sex",columnDefinition="char(2) CHECK(_sex IN ('男','女',null))")
// //使用一个表做主键生成器
// @TableGenerator(
// //生成器名
// name="userGen"
// //表名
// ,table="ID_GEN"
// //主键列
// ,pkColumnName="GEN_KEY"
// //生成器的值
// ,valueColumnName="GEN_VALUE"
// //主键列的值
// ,pkColumnValue="USER_ID"
// //每次的递增
// ,allocationSize=3
// )
//hibernate扩展的通用生成器
@GenericGenerator(
//生成器名
name="myIncrement"
//生成策略:使用hibernate的生成策略
// ,strategy="increment"
,strategy="hilo"
//参数(比如hibernate的生成策略:hilo)
,parameters={
//配置两参数
@Parameter(name="table",value="hibernate_key")
,@Parameter(name="column",value="next_value")
}
)
//主键生成策略
@GeneratedValue(
//指定生成策略:自动选择一种适合的生成策略
// strategy = GenerationType.AUTO
//生成标识列,主键生成标识列,由数据库生成
// strategy = GenerationType.IDENTITY
//使用序列生成策略,需要指定生成器的序列名
// strategy = GenerationType.SEQUENCE
//需要一个表生成器
// strategy = GenerationType.TABLE,
//指定生成器(就是序列的名字),指定生成器就可以不用指定生成策略了
generator="myIncrement"
)
public Integer getId() {
return id;
}
public char getSex() {
return sex;
}
//各种set、get方法
……
}b) 添加数据
@Test
public void testAdd() {// 解析配置(没变化) Configuration cfg = new Configuration().configure(); // 创建一个服务注册对象 ServiceRegistry refistry = new ServiceRegistryBuilder() // 用配置信息去申请一个服务注册对象 .applySettings(cfg.getProperties()) // 创建服务注册对象 .buildServiceRegistry(); // 这是与hibernate3.6以下版本的区别 // 解析对象创建session工厂,使用服务注册对象 SessionFactory factory = cfg.buildSessionFactory(refistry); // Session session = factory.openSession(); // 使用getCurrentSession()获得session,提交之前获取的session都是同一个 // 需要在配置中配置session上下文环境,有jta和thread等,提交后自动关闭session Session session = factory.getCurrentSession(); session = factory.getCurrentSession(); try { session.beginTransaction(); session = factory.getCurrentSession(); User user = new User(); user.setUsername("lisi"); user.setPassword("123"); user.setSex('女'); user.setAge(22); session.save(user); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); } // finally { // session.close(); // } session = factory.getCurrentSession();
}
c) session工厂的getCurrentSession方法
配置factory.getCurrentSession()中的session上下文:
在hibernate.cfg.xml中配置:
JTASessionContext:分布式的使用这个 <property name="hibernate.current_session_context_class">jta</property> ThreadLocalSessionContext:在我们自己的线程当中使用这个 <property name="hibernate.current_session_context_class">thread</property>
ManagedSessionContext:自己管理,灵活性大,使用这个
- 多对一单向关联注解配置
a) Group.java
@Entity
@Table(name = "t_group",
uniqueConstraints = {
@UniqueConstraint(columnNames = { "groupName" })
}
)
public class Group {private int id;
private String groupName;@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public String getGroupName() {
public void setGroupName(String groupName) {
return groupName;
}
this.groupName = groupName;
}
}b) User.java
@Entity
@Table(name = "t_user", schema = "hibernate")
public class User {private Integer id;
private String username;
private String password;
private Integer age;
private char sex;
private Group group = null;// 多对一配置
@ManyToOne(
//全部级联
cascade = {CascadeType.ALL}
//一般不用配置,只有使用接口编程时使用,
//比如set方法和get方法使用的参数都是接口,要指定接口的实现类
,targetEntity=Group.class
)
//生成外键,默认是:属性名_id
@JoinColumn(name="groupId")
public Group getGroup() {
return group;
}public void setGroup(Group group) {
@Id
this.group = group;
}
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return id;
}
//各种set、get方法
……
} c) hibernate.cfg.xml
……
<!—
配置映射实体类
-->d) 使用注解映射多对一单向关联
/**测试Many2One单向关联添加
*/
@Test
public void testAdd() {Group group = new Group();
group.setGroupName("二组");User user = new User();
user.setUsername("李四");
user.setPassword("123");
user.setSex('女');
user.setAge(22);
user.setGroup(group);Session session = Hibernate4Util.getCurrentSession();
try {
session.beginTransaction();session.save(user); session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback(); e.printStackTrace();
}
}
/**
测试Many2One单向关联重建
*/
@Test
public void testQuery() {Session session = Hibernate4Util.getCurrentSession();
try {
session.beginTransaction();User user = (User) session.get(User.class, 1); System.out.println(user.getUsername()); // 默认链接查询 System.out.println(user.getGroup().getGroupName()); session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback(); e.printStackTrace();
}
}
- 一对多多对一双向关联注解配置
a) Group.java
@Entity
@Table(name = "t_group", uniqueConstraints = {
@UniqueConstraint(columnNames = { "groupName" }) })
public class Group {private int id;
private String groupName;
private Setusers = new HashSet (); @OneToMany(
// 级联
cascade = { CascadeType.ALL }
// 放弃维护数据,去User中找关于我本身(Group)的User
, mappedBy = "group"
// 删除孤儿(如果为false,删除组时将相关用户组id置为null)
// ,orphanRemoval=true
//抓取策略
// ,fetch=FetchType.EAGER//没用,不配懒加载还好
)
// @JoinColumn(name="groupId")
public SetgetUsers() {
return users;
}public void setUsers(Set
users) {
this.users = users;
}@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public String getGroupName() {
return groupName;
}public void setGroupName(String groupName) {
this.groupName = groupName;
} - 一对一唯一外键双向关联注解配置
a) Employee.java
@Entity
@Table(name = "t_emp")
public class Employee {private int id;
private String name;
// 先有员工,才有用户
private User user;// 放弃维护数据,去User中找关于我本身(Employee)的User
@Id
@OneToOne(cascade = CascadeType.ALL, mappedBy = "emp")
public User getUser() {
return user;
}
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
}b) User.java
/**
从表(从表引用主表id)
*/
@Entity
@Table(name = "t_user", schema = "hibernate")
public class User {private Integer id;
private String username;
private String password;
private Integer age;
private char sex;private Employee emp;
// 唯一外键关联
@OneToOne
@JoinColumn(name = "empId", unique = true)
public Employee getEmp() {
return emp;
}@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
//各种set、get方法
……
}
- 共享主键一对一双向关联注解配置
a) User.java
/**
共享主键
*/
@Entity
@Table(name = "t_user", schema = "hibernate")
public class User {private Integer id;
private String username;
private String password;
private Integer age;
private char sex;
private Employee emp;@OneToOne
// 将emp设为主键关联
@PrimaryKeyJoinColumn
public Employee getEmp() {
return emp;
}// 使用外键emp的id作为我的主键,共享主键
@Id
// 主键生成器配置
@GenericGenerator(name = "foreignKey", strategy = "foreign", parameters = { @Parameter(name = "property", value = "emp") })
@GeneratedValue(generator = "foreignKey")
public Integer getId() {
return id;
}
//各种set、get方法
……
}
- 多对多双向关联注解配置
a) Book.java
@Entity
@Table(name = "t_book")
public class Book {private int id;
private String bookName;
private Setauthors = new HashSet (); @ManyToMany(cascade = CascadeType.ALL,
@Id
// 去Author中找关于我本身(Book)的Author
mappedBy = "books")
public SetgetAuthors() {
return authors;
}
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
}b) Author.java
@Entity
@Table(name = "t_author")
public class Author {private int id;
private String name;
private Setbooks = new HashSet (); @ManyToMany(cascade = CascadeType.ALL,
// 左外联
fetch = FetchType.EAGER)
@JoinTable(name = "t_author_book",
// 我在关系表中的id
joinColumns = { @JoinColumn(name = "authorId") },
// 放弃维护数据的对方在表中的id
inverseJoinColumns = { @JoinColumn(name = "bookId") })
public SetgetBooks() {
return books;
}@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
} - 组件映射注解配置
a) Contact.java
private String tel;
@Embeddable
public class Contact {
private String phone;
private String qq;
private String email;
//各种set、get方法
……
}b) Address.java
@Embeddable
public class Address {private String busiAddress;
private String homeAddress;private Contact contact;
@Embedded
public Contact getContact() {
return contact;
}
//各种set、get方法
……
}c) Author.java
@Entity
@Table(name = "t_author")
public class Author {private int id;
private String name;
private Address address;@Embedded
@AttributeOverrides({//重新定义列
@AttributeOverride(name="busiAddress",
column=@Column(name="busi_Address",length=200)
),
@AttributeOverride(name="homeAddress",
column=@Column(name="home_Address",length=200)
)
})
public Address getAddress() {
return address;
}@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
} - 集合映射注解配置(SET、LIST、MAP集合)
a) Book.java
@Entity
@Table(name = "t_book")
public class Book {private int id;
private String bookName;/**
- 集合配置一定不能放弃维护数据
*/
private Setimages = new HashSet ();
private ListimageList = new ArrayList ();
private Map<String, String> imageMap = new HashMap<String, String>();
/**
- Set集合配置
*/
@ElementCollection
@JoinTable(name = "t_images", joinColumns = { @JoinColumn(name = "book_Id") })
@Column(name = "image")
public SetgetImages() {
return images;
}
/**
- List集合配置
*/
@ElementCollection
@JoinTable(name = "t_imageList", joinColumns = { @JoinColumn(name = "book_Id") })
@Column(name = "image")
@IndexColumn(name = "list_index")
public ListgetImageList() {
return imageList;
}
/**
- Map集合配置
*/
@ElementCollection
@JoinTable(name = "t_imageMap", joinColumns = { @JoinColumn(name = "book_Id") })
@Column(name = "map_value")
@MapKeyColumn(name = "map_key")
public Map<String, String> getImageMap() {
return imageMap;
}
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
}b) User.java
@Entity
@Table(name = "t_user")
public class User {private Integer id;
private String username;
private String password;
private Integer age;
private char sex;@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
//各种set、get方法
……
} - 集合配置一定不能放弃维护数据
c) Group.java
@Entity
@Table(
name = "t_group",
uniqueConstraints = {
@UniqueConstraint(columnNames = { "groupName" })
}
)
public class Group {
private int id; private String groupName; // 用List性能没有Set好,还可能会放重复的值,不建议使用 private List<User> userList = new ArrayList<User>(); private Map<String, User> userMap = new HashMap<String, User>(); /** * List实体对象集合配置 */ @OneToMany(cascade = { CascadeType.ALL }) @JoinTable( name = "t_userList", joinColumns = { @JoinColumn(name = "group_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") } ) @IndexColumn(name = "list_index") public List<User> getUserList() { return userList; } /** * Map实体对象集合配置 */ @OneToMany(cascade = CascadeType.ALL) @JoinTable( name = "t_userMap", joinColumns = { @JoinColumn(name = "group_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") } ) // @Column(name = "key_value")//无效 @MapKeyColumn(name = "map_key") public Map<String, User> getUserMap() { return userMap; } @Id @GeneratedValue(strategy = GenerationType.AUTO) public int getId() { return id; }
//各种set、get方法
……
}
d) 使用集合映射
@Test
public void testAdd() {
Book book = new Book(); book.setBookName("Java编程思想"); /** * 测试Set集合映射 */ book.getImages().add("1.jpg"); book.getImages().add("2.jpg"); book.getImages().add("3.jpg"); /** * 测试List集合映射 */ book.getImageList().add("1.jpg"); book.getImageList().add("2.jpg"); book.getImageList().add("3.jpg"); /** * 测试Map集合映射 */ book.getImageMap().put("a1", "1.jpg"); book.getImageMap().put("a2", "2.jpg"); book.getImageMap().put("a3", "3.jpg"); Session session = Hibernate4Util.getCurrentSession(); try { session.beginTransaction(); // ..... session.save(book); session.getTransaction().commit(); } catch (Exception e) { session.getTransaction().rollback(); e.printStackTrace(); } } @Test public void testAdd2() { User user1 = new User(); user1.setUsername("李四"); user1.setPassword("54545"); user1.setAge(22); user1.setSex('女'); User user2 = new User(); user2.setUsername("王五"); user2.setPassword("2522"); user2.setAge(23); user2.setSex('女'); User user3 = new User(); user3.setUsername("张三"); user3.setPassword("1111"); user3.setAge(20); user3.setSex('男'); User user4 = new User(); user4.setUsername("赵六"); user4.setPassword("22222"); user4.setAge(20); user4.setSex('女');
Group group1 = new Group();
group1.setGroupName("一组");
Group group2 = new Group();
group2.setGroupName("二组");
/**
* 测试List实体集合映射
*/
group1.getUserList().add(user1);
group1.getUserList().add(user2);
/**
* 测试Map实体集合映射
*/
group2.getUserMap().put("u3", user3);
group2.getUserMap().put("u4", user4);
Session session = Hibernate4Util.getCurrentSession();
try {
session.beginTransaction();
// .....
session.save(group1);
session.save(group2);
session.getTransaction().commit();
} catch (Exception e) {
session.getTransaction().rollback(); e.printStackTrace(); } }
- 单表继承映射注解配置
a) Dog.java
@Entity
@DiscriminatorValue("D")
public class Dog extends Animal {private double speed;
public double getSpeed() {
public void setSpeed(double speed) {
return speed;
}
this.speed = speed;
}
}b) Pig.java
@Entity
@DiscriminatorValue("P")
public class Pig extends Animal {private double weight;
public double getWeight() {
public void setWeight(double weight) {
return weight;
}
this.weight = weight;
}
}c) Animal.java
@Entity
@Table(name = "t_animal")
// 继承树一个表
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name = "discriminator",
discriminatorType = DiscriminatorType.STRING
)
public class Animal {private int id;
private String name;@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
//各种set、get方法
……
} - 每个子类一张表继承映射注解配置
a) Pig.java
@Entity
@Table(name = "t_pig")
public class Pig extends Animal {
private double weight;public double getWeight() {
public void setWeight(double weight) {
return weight;
}
this.weight = weight;
}
}b) Dog.java
@Entity
@Table(name = "t_dog")
public class Dog extends Animal {
private double speed;public double getSpeed() {
public void setSpeed(double speed) {
return speed;
}
this.speed = speed;
}
}c) Animal.java
@Entity
@Table(name = "t_animal")
// 每个子类一个表(不常用)
@Inheritance(strategy = InheritanceType.JOINED)
public class Animal {private int id;
private String name;@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}
} - 每个具体类一张表继承映射注解配置
a) Animal.java
@Entity
@Table(name = "t_animal")
// 每个具体类一张表(不常用)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Animal {private int id;
private String name;// 每个具体类一张表,id生成策略不能用auto了
// 使用hibernate生成,
@Id
@GenericGenerator(name = "mystrategy", strategy = "increment")
@GeneratedValue(generator = "mystrategy")
public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public String getName() {
public void setName(String name) {
return name;
}
this.name = name;
}
}b) Dog.java
@Entity
@Table(name = "t_dog")
public class Dog extends Animal {private double speed;
public double getSpeed() {
return speed;
}public void setSpeed(double speed) {
this.speed = speed;
}
}
c) Pig.java
@Entity
@Table(name = "t_pig")
public class Pig extends Animal {
private double weight; public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; }
}
- hibernate4的二级缓存配置及应用注解使用
a) 用到的包以及文件
ehcache.xml 配置文件
ehcache-core-2.4.3.jar
hibernate-ehcache-4.2.16.Final.jar
slf4j-api-1.6.1.jar
slf4j-log4j12-1.6.1-sources.jar slf4j-api-1.6.1.jar的桥梁b) hibernate.cfg.xml中:
true true <property name="hibernate.cache.region.factory_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory </property>
c) 给某个类启用二级缓存
@Entity
@Table(name = "t_sinal")
// 启用缓存
@Cacheable
// 缓存方式
@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Sinal {
……
}
或者在hibernate.cfg.xml中: