首页 > 其他分享 >重拾Hibernate框架——实体类、主键生成策略、session绑定本地线程

重拾Hibernate框架——实体类、主键生成策略、session绑定本地线程

时间:2022-11-28 20:31:08浏览次数:33  
标签:实体类 Hibernate session User 主键 user


目录

  • ​​目录​​
  • ​​实体类持久化类的编写规则​​
  • ​​Hibernate主键生成策略​​
  • ​实体类操作​
  • ​​案例准备​​
  • ​对实体类CRUD操作​
  • ​​添加操作​​
  • ​​查询操作​​
  • ​​修改操作​​
  • ​​删除操作​​
  • ​​saveOrUpdate方法​​
  • ​​实体类对象状态​​
  • ​​Hibernate一级缓存​​
  • ​Hibernate事务操作​
  • ​​规范写法​​
  • ​​案例​​
  • ​Hibernate中session绑定本地线程​
  • ​​实现session与本地线程当前线程绑定​​
  • ​Hibernate的其他API​
  • ​​Query对象​​
  • ​​Criteria对象​​
  • ​​SQLQuery对象​​


实体类(持久化类)的编写规则

  1. 属性私有化,即private修饰;
  2. 属性提供getter和setter方法;
  3. 要求实体类提供一个属性,并作为唯一值(一般使用ID值);
  4. 实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。

为什么“实体类属性建议使用基本数据类型对应的包装类,而不使用基本数据类型。”?
  假设存在这么一个实体类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

实现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.java

package 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,session,User,主键,user
From: https://blog.51cto.com/u_15894233/5893665

相关文章

  • C#-MVC-内置对象-Request、Response、Session、Cookie、Application、Server
    Controllers文件夹Controllers文件夹包含负责处理用户输入和响应的控制类。MVC要求所有控制器文件的名称以“Controller”结尾。在下例中,VisualWebDeveloper已经......
  • Cookie、Session与Token
    Cookie Cookie是一个http请求首部,当服务端响应头上标记着setCookie时,可以设置此cookie到当前域名下。浏览器端会将此cookie以kv的形式存储到本地文件中Session sess......
  • 数据库主键的生成
    1.分布式唯一ID特性在业务开发中,会存在大量的场景都需要唯一ID来进行标识。比如,用户需要唯一身份标识;商品需要唯一标识;消息需要唯一标识;事件需要唯一标识等等。尤其......
  • mybatis-获取SqlSession
    一、构建SqlSessionFactorySqlSessionFactoryBuilder.build(InputStreaminputStream,Stringenvironment,Propertiesproperties)publicSqlSessionFactorybuild(I......
  • 【认证机制】4-Cookie-Session基本概念
    1.  Cookie1.1概述Cookie是一种在远程浏览器端存储数据并以此来跟踪和识别用户的机制。Cookie是Web服务器暂时存储在用户硬盘上的一个文本文件,当用户再次访问Web网......
  • 基于session登陆进行演变
    1.发送手机验证码:提交手机号-检验手机号-生成验证码->保存到session->发送验证码publicResultsendCode(Stringphone,HttpSessionsession){//1.校......
  • 基于session登陆的演变
    1.发送手机验证码:提交手机号-检验手机号-生成验证码->保存到session->发送验证码publicResultsendCode(Stringphone,HttpSessionsession){//1.......
  • Java Web中requset,session,application 的作用域及区别
    三者概述requset概述:request是表示一个请求,只要发出一个请求就会创建一个request用处:常用于服务器间同一请求不同页面之间的参数传递,常应用于表单的控件值传递。sessio......
  • php session_start() open failed Permission denied,session.save_path的解决办法
    1.背景公司最近来了一个新游戏项目,游戏入口程序居然见到了许多年未见的php环境,虽然很久没有接触,但是这种东西不是简简单单嘛,怀着这种心态,慢慢的走进了一个小坑,搞了1个......
  • 自动注册实体类到EntityFramework Core上下文,并适配ABP及ABP VNext
    继上篇文章(EFCore懒人小技巧之拒绝DbSet)之后,最近笔者把这个小功能单独封装成一个扩展方法并开源,欢迎交流和Star~GitHub: EntityFrameworkCore.Extension.AutoMappingNug......