重拾Hibernate框架——实体类、主键生成策略、session绑定本地线程
2017-05-20 21:43
585 查看
目录
目录实体类持久化类的编写规则
Hibernate主键生成策略
实体类操作
案例准备
对实体类CRUD操作
添加操作
查询操作
修改操作
删除操作
saveOrUpdate方法
实体类对象状态
Hibernate一级缓存
Hibernate事务操作
规范写法
案例
Hibernate中session绑定本地线程
实现session与本地线程当前线程绑定
Hibernate的其他API
Query对象
Criteria对象
SQLQuery对象
实体类(持久化类)的编写规则
属性私有化,即private修饰;属性提供getter和setter方法;
要求实体类提供一个属性,并作为唯一值(一般使用ID值);
实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。
为什么“实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。”?
假设存在这么一个实体类Student类,具有int score属性,那么:
当学生分数为0时,score = 0;当学生没有参加考试时,int类型的score属性就无法表示这个含义了。
但是如果score为Integer类型,则可以以 score = null 进行表示。
Hibernate主键生成策略
实体类被要求提供一个属性作为唯一值,该属性就对应数据库表中的主键。在Hibernate中主键由配置好的策略进行生成。(主键生成策略在对应的实体类映射配置文件中进行设置)
如:
<!-- id标签 name属性:实体类中作为唯一标识的属性的名称 column属性:生成的表字段名称 --> <id name="uid" column="uid"> <!-- 设置数据库表中ID的增长策略 native:生成表的id是主键自动增长的。 --> <generator class="native"/> </id>
主键生成策略有:(列举出几个常见的)
1. increment:用于long、short或int类型,由Hibernate自动以递增的方式生成唯一标识符,每次增量为1。只有当没有其他进程向同一张表中插入数据时才可以使用,不能在集群环境下使用。适用于代理主键。
2. identity:采用底层数据库本身提供的主键生成标识符,条件是数据库支持自动增长数据类型。在MySQL数据库中可以使用该生成器,该生成器要求在数据库中把主键定义成自增长类型。适用于代理主键。Oracle数据库并不适用。
3. sequence:Hibernate根据底层数据库序列生成标识符。条件是数据库之间序列。适用于代理主键。在Oracle数据库中可以使用该生成器。
4. native:根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilo三种生成器中的一种,适合跨数据库平台开发。适用于代理主键。
5. uuid:使用128位的UUID算法计算一个唯一的值,会使用IP地址及相关的计算机硬件信息。计算结果位32位的16进制数,对应的主键类型必须为String。
注:
increment和identity的区别:这两种主键生成方式都是提供自增长策略,但是原理并不一样。increment的主键自增长由Hibernate维护,而identity的主键自增长由底层数据库维护。如果采用MySQL的自增长(这里假设使用MySQL数据库,且主键生成策略设置为identity),插入数据时Hibernate生成的SQL语句中将不包含id主键列数据。该主键的当前值、下一个值由数据库自己维护。如果使用Hibernate的自增长(即设置了increment主键生成策略),插入数据时Hibernate生成的SQL语句将包含id主键列,并由Hibernate维护该主键的当前值以及下一个值。
increment,自增长类型,由Hibernate而不是数据库维护,因此即使Oracle等不支持自增长类型的数据库也可以使用。
实体类操作
案例准备
(以下说明均基于该案例进行说明)实体类 User.java
package com.wm103.entity; import java.io.Serializable; public class User implements Serializable { /*Hibernate要求实体类有一个属性是唯一的。*/ private int uid; private String username; private String password; private String address; public int getUid() { return uid; } public void setUid(int uid) { this.uid = uid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "User{" + "uid=" + uid + ", username='" + username + '\'' + ", password='" + password + '\'' + ", address='" + address + '\'' + '}'; } }
实体类的映射文件 User.hbm.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.wm103.entity.User" table="t_user"> <id name="uid" column="uid"> <generator class="native"/> </id> <property name="username" column="username"></property> <property name="password" column="password"></property> <property name="address" column="address"></property> </class> </hibernate-mapping>
核心配置文件 hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql:///hibernate_day01?useUnicode=true&characterEncoding=UTF-8</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="hbm2ddl.auto">update</property> <mapping resource="com/wm103/entity/User.hbm.xml"/> </session-factory> </hibernate-configuration>
Hibernate工具类 HibernateUtil.java
package com.wm103.utils; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; /** * Created by DreamBoy on 2017/5/19. */ public class HibernateUtil { // 单态模式的SessionFactory private static final SessionFactory sessionFactory; static { // 采用默认的hibernate.cfg.xml来启动一个Configuration的实例 Configuration cfg = new Configuration().configure(); sessionFactory = cfg.buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void main(String[] args) { System.out.println(getSessionFactory()); } }
测试类 HibernateDemo.java
package com.wm103.hibernatetest; import com.wm103.entity.User; import com.wm103.utils.HibernateUtil; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; /** * Created by DreamBoy on 2017/5/19. */ public class HibernateDemo { public void test() { // 1. 调用工具类得到sessionFactory SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 2. 获取session Session session = sessionFactory.openSession(); // 3. 开启事务 Transaction tx = session.beginTransaction(); // 4. 具体逻辑 // 后续提及的案例代码放在这里!!! // 5. 提交事务 tx.commit(); // 6. 关闭资源 session.close(); sessionFactory.close(); } }
对实体类CRUD操作
添加操作
调用session里面的save方法,如:User user = new User(); user.setUsername("梦小白"); user.setPassword("123"); user.setAddress("China"); session.save(user);
查询操作
调用session里面的get方法,如:User user = session.get(User.class, 2); System.out.println(user);
修改操作
调用session里面的update方法,如:User user = session.get(User.class, 1); user.setUsername("DreamBoy"); session.update(user);
删除操作
第一种 根据ID查询到的对象User user = session.get(User.class, 2); session.delete(user);
第二种 创建新对象设置主键ID值
User user = new User(); user.setUid(3); session.delete(user);
saveOrUpdate方法
既能实现添加操作,又能实现修改操作。如:实现添加操作
User user = new User(); user.setUsername("User007"); user.setPassword("007"); user.setAddress("地下城"); // 实体类对象状态是瞬时态时,saveOrUpdate执行的是添加操作 session.saveOrUpdate(user);
实现修改操作
User user = session.get(User.class, 1); user.setUsername("DreamBoy"); // 实体类对象状态是持久态时,saveOrUpdate执行的是修改操作 session.saveOrUpdate(user);
实体类对象状态
实体类对象有三种状态:(1)瞬时态:对象里面没有ID值,对象与session没有关联。如:
User user = new User(); user.setUserName("haha"); user.setPassword("1234"); user.setAddress("China"); session.save(user);
在这里添加user记录以前,user对象既没有ID值也没有与session关联,此时user对象处于瞬时态。
(2)持久态:对象里面有ID值,且与session有关联。如:
User user = session.get(User.class, 1);
(3)托管态:对象里面有ID值,但是与session没有关系。
User user = new User(); user.setUid(3); session.delete(user);
在这里执行delete方法之前user对象处于托管态。
Hibernate一级缓存
(1)Hibernate一级缓存的特点:Hibernate的一级缓存是默认打开的
Hibernate的一级缓存使用范围,是session范围,即从session创建到session关闭
Hibernate的一级缓存中,存储数据必须是持久态数据
(2)特性:持久态下修改实体类对象属性会自动更新数据库,如:
User user = session.get(User.class, 1); user.setUsername("DreamBoy"); // session.update(user); // 这里不调用,同样在提交事务的时候,也会进行更新操作
Hibernate事务操作
规范写法
try { // 开启事务 // ... // 提交事务 } catch() { // 回滚事务 } finally { // 关闭资源 }
案例
@Test public void testTx() { SessionFactory sessionFactory = null; Session session = null; Transaction tx = null; try { sessionFactory = HibernateUtil.getSessionFactory(); session = sessionFactory.openSession(); tx = session.beginTransaction(); User user = new User(); user.setUsername("1530"); user.setPassword("0521"); user.setAddress("guangzhou"); session.save(user); tx.commit(); } catch (Exception e) { tx.rollback(); } finally { session.close(); sessionFactory.close(); } }
Hibernate中session绑定本地线程
SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session实例。而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致 Session 数据存取逻辑混乱.因此创建的Session实例必须在本地线程上运行,使之总与当前的线程相关。参考:
http://blog.sina.com.cn/s/blog_7ffb8dd5010146i3.html http://www.cnblogs.com/shipengzhi/articles/2102055.html[/code]实现session与本地线程(当前线程)绑定
(1)在Hibernate的核心配置文件中配置<property name="hibernate.current_session_context_class">thread</property>
(2)调用sessionFactory的getCurrentSession方法得到当前线程相关的sessio对象public static Session getSession() { return sessionFactory.getCurrentSession(); }
注:获取与本地线程绑定的session对象后,手动关闭session会报错:org.hibernate.SessionException: Session was already closed。因为与本地线程绑定的session,在本地线程结束后就会被关闭,我们不需要在手动session.close()。
HibernateUtil.javapackage com.wm103.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
/**
* Created by DreamBoy on 2017/5/19.
*/
public class HibernateUtil {
// 单态模式的SessionFactory
private static final SessionFactory sessionFactory;
static {
// 采用默认的hibernate.cfg.xml来启动一个Configuration的实例
Configuration cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() { return sessionFactory.getCurrentSession(); }
public static void main(String[] args) {
System.out.println(getSessionFactory());
}
}
测试案例:@Test public void testGetSession() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); User user = new User(); user.setUsername("1654"); user.setPassword("0521"); user.setAddress("guangzhou"); session.save(user); tx.commit(); } catch (Exception e) { tx.rollback(); } }Hibernate的其他API
(这里只演示查询表中所有数据的功能)Query对象
使用Query对象,我们不需要编写SQL语句,但是需要写HQL(HQL,Hibernate Query Language)语句。HQL语法类似于SQL,不同的是HQL是一种完全面向对象的语言,能够直接查询实体类及属性。而SQL语句操作的是数据库中的表和表中的字段。
查询表中所有数据的HQL:from 实体类名称。如:@Test public void testQuery() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); Query query = session.createQuery("from User"); List<User> list = query.list(); for (User user : list) { System.out.println(user); } tx.commit(); } catch (Exception e) { tx.rollback(); } }Criteria对象
@Test public void testCriteria() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); Criteria criteria = session.createCriteria(User.class); List<User> list = criteria.list(); for (User user : list) { System.out.println(user); } tx.commit(); } catch (Exception e) { tx.rollback(); } }SQLQuery对象
@Test public void testSQLQuery() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); SQLQuery sqlQuery = session.createSQLQuery("SELECT * FROM t_user"); // list方法默认返回的是一个List集合,且集合中的元素为对象数组Object[] /*List<Object[]> list = sqlQuery.list(); for (Object[] obj : list) { System.out.println(Arrays.toString(obj)); }*/ // 返回一个List集合,且集合中的元素为实体类对象 sqlQuery.addEntity(User.class); List<User> list = sqlQuery.list(); for (User user : list) { System.out.println(user); } tx.commit(); } catch (Exception e) { tx.rollback(); } }
相关文章推荐
- hibernate框架(4)---主键生成策略
- hibernate主键生成策略---【小白系列】0基础到熟练应用hibernate框架(七)
- 【Hibernate框架开发之四】Hibernate-Annotation常用的注解归总&&ID的生成策略&&联合主键
- hibernate 管理Session:Session 对象的生命周期与本地线程绑定
- hibernate_day02_02_实体类编写规则和03_hibernate主键生成策略
- hibernate 本地线程绑定session
- 【Hibernate框架开发之四】Annotation注解归总&ID生成策略&联合主键
- Hibernate中Session与本地线程绑定
- [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定
- hibernate事务代码规范和session与本地线程绑定
- Hibernate中Session与本地线程作绑定
- Hibernate中Session与本地线程绑定
- hibernate框架绑定本地的session(八)
- hibernate的实体类编写规则与主键生成策略
- Hibernate中Session与本地线程作绑定
- hibernate框架学习笔记4:主键生成策略、对象状态
- Hibernate -- Session的主键生成策略
- Hibernate -- Session的主键生成策略
- 【Hibernate框架开发之四】Hibernate-Annotation常用的注解归总&&ID的生成策略&&联合主键
- hibernate中session与本地线程绑定