Hibernate入门篇 - ORM真香

Hibernate ORM

Hibernate架构

Hibernate架构图:
在这里插入图片描述

Hibernate 使用不同的现存 Java API,比如 JDBC,Java 事务 API(JTA),以及 Java 命名和目录界面(JNDI)。JDBC 提供了一个基本的抽象级别的通用关系数据库的功能, Hibernate 支持几乎所有带有 JDBC 驱动的数据库。JNDI 和 JTA 允许 Hibernate 与 J2EE 应用程序服务器相集成。

配置对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

  • 数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.propertieshibernate.cfg.xml
  • 类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

SessionFactory对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

  • 数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.propertieshibernate.cfg.xml
  • 类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

Session对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

  • 数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.propertieshibernate.cfg.xml
  • 类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

Transaction对象

配置对象是你在任何 Hibernate 应用程序中创造的第一个 Hibernate 对象,并且经常只在应用程序初始化期间创造。它代表了 Hibernate 所需一个配置或属性文件。配置对象提供了两种基础组件。

  • 数据库连接:由 Hibernate 支持的一个或多个配置文件处理。这些文件是 hibernate.propertieshibernate.cfg.xml
  • 类映射设置:这个组件创造了 Java 类和数据库表格之间的联系。

Query对象

Query 对象使用 SQL 或者 Hibernate 查询语言(HQL)字符串在数据库中来检索数据并创造对象。一个查询的实例被用于连结查询参数,限制由查询返回的结果数量,并最终执行查询。

Criteria

Criteria 对象被用于创造和执行面向规则查询的对象来检索对象。可以利用该类来完成非sql语句的数据过滤查询。

引入Hibernate

手动引入

在Hibernate官网http://hibernate.org/orm/releases/下载合适版本的资料,其中包括hibernate的源码、编译好的jar包和文档信息。

对于普通使用只需要把lib\required目录下的jar包引入项目,对于缓存的使用,需要引入lib\optional\ehcache目录下的EHCache的jar包。

maven

hibernate包

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.4.21.Final</version>
</dependency>

缓存Ehcache

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-ehcache</artifactId>
    <version>5.4.21.Final</version>
</dependency>

Hibernate6目前还处于测试版。

使用之前还需要引入对应自己DataBase的JDBC驱动。

hibernate.cfg.xml配置文件

hibernate.cfg.xml是hibernate配置文件的默认文件名,只需要将hibernate.cfg.xml文件放在项目目录下,hibernate将自动读取文件中的配置。(对于普通的java项目,hibernate.cfg.xml应该放在src目录下)

通常需要配置SQL方言、连接驱动、数据库url地址、用户名和密码等。可以使用mapping标签来指示映射文件路径,可以同hibernate的配置文件放在项目根目录下。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration SYSTEM
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--    配置一个session工厂-->
    <session-factory>
<!--        sql方言-->
        <property name="hibernate.dialect">
            org.hibernate.dialect.MySQLDialect
        </property>

<!--        jdbc驱动-->
        <property name="hibernate.connection.driver_class">
            com.mysql.cj.jdbc.Driver
        </property>
        
<!--        数据库链接-->
        <property name="hibernate.connection.url">
            jdbc:mysql://localhost:3306/hibernate_study?serverTimezone=UTC
        </property>

<!--        用户名-->
        <property name="hibernate.connection.username">
            dev
        </property>

<!--        密码-->
        <property name="hibernate.connection.password">
            123456
        </property>

<!--        映射文件-->
        <!-- 支持package、class、file、jar -->
        <mapping resource="User.hbm.xml" />
    </session-factory>
</hibernate-configuration>

几个重要的配置属性

NO属性和描述
1hibernate.connection.datasource
在应用程序服务器环境中您正在使用的应用程序 JNDI 名。
2hibernate.jndi.class
JNDI 的 InitialContext 类。
3**hibernate.jndi. **
在 JNDI的 InitialContext 类中通过任何你想要的 Java 命名和目录接口属性。
4hibernate.jndi.url
为 JNDI 提供 URL。
5**hibernate.connection.username **
数据库用户名。
6**hibernate.connection.password **
数据库密码。

数据库方言

数据库方言属性
DB2org.hibernate.dialect.DB2Dialect
HSQLDBorg.hibernate.dialect.HSQLDialect
HypersonicSQLorg.hibernate.dialect.HSQLDialect
Informixorg.hibernate.dialect.InformixDialect
Ingresorg.hibernate.dialect.IngresDialect
Interbaseorg.hibernate.dialect.InterbaseDialect
Microsoft SQL Server 2000org.hibernate.dialect.SQLServerDialect
Microsoft SQL Server 2005org.hibernate.dialect.SQLServer2005Dialect
Microsoft SQL Server 2008org.hibernate.dialect.SQLServer2008Dialect
MySQLorg.hibernate.dialect.MySQLDialect
Oracle (any version)org.hibernate.dialect.OracleDialect
Oracle 11gorg.hibernate.dialect.Oracle10gDialect
Oracle 10gorg.hibernate.dialect.Oracle10gDialect
Oracle 9iorg.hibernate.dialect.Oracle9iDialect
PostgreSQLorg.hibernate.dialect.PostgreSQLDialect
Progressorg.hibernate.dialect.ProgressDialect
SAP DBorg.hibernate.dialect.SAPDBDialect
Sybaseorg.hibernate.dialect.SybaseDialect
Sybase Anywhereorg.hibernate.dialect.SybaseAnywhereDialec

简单的XML映射文件

所有的Entity应该是按照java bean的要求编写的POJO对象,以User Entity为例。

User Entity:

package cn.llzero.entity;

import java.io.Serializable;

public class User implements Serializable {
    private Integer id;

    private String name;

    private String pass;

    private Character sex;

    public Integer getId() {
        return id;
    }

    public User setId(Integer id) {
        this.id = id;
        return this;
    }

    public String getName() {
        return name;
    }

    public User setName(String name) {
        this.name = name;
        return this;
    }

    public String getPass() {
        return pass;
    }

    public User setPass(String pass) {
        this.pass = pass;
        return this;
    }

    public Character getSex() {
        return sex;
    }

    public User setSex(Character sex) {
        this.sex = sex;
        return this;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pass='" + pass + '\'' +
                ", sex=" + sex +
                '}';
    }
}

XML映射文件(User.hbm.xml):

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="cn.llzero.entity.User" table="user">
        <meta attribute="description">
            User映射,学习Hibernate
        </meta>

        <id name="id" column="id" type="integer" >
            <generator class="native" />
        </id>

        <property name="name" column="name" unique="true" type="string" />

        <property name="pass" column="pass" type="string"/>

        <property name="sex" column="sex" type="char"/>
    </class>
</hibernate-mapping>

name => 对应实体的属性, column => 数据库字段, type指示了数据的类型,该属性建议使用hibernate的预设值。

hibernate type预设值

当你准备一个 Hibernate 映射文件时,我们已经看到你把 Java 数据类型映射到了 RDBMS 数据格式。在映射文件中已经声明被使用的 types 不是 Java 数据类型;它们也不是 SQL 数据库类型。这种类型被称为 Hibernate 映射类型,可以从 Java 翻译成 SQL,反之亦然。

在这一章中列举出所有的基础,日期和时间,大型数据对象,和其它内嵌的映射数据类型。

原始类型
映射类型Java 类型ANSI SQL 类型
integerint 或 java.lang.IntegerINTEGER
longlong 或 java.lang.LongBIGINT
shortshort 或 java.lang.ShortSMALLINT
floatfloat 或 java.lang.FloatFLOAT
doubledouble 或 java.lang.DoubleDOUBLE
big_decimaljava.math.BigDecimalNUMERIC
characterjava.lang.StringCHAR(1)
stringjava.lang.StringVARCHAR
bytebyte 或 java.lang.ByteTINYINT
booleanboolean 或 java.lang.BooleanBIT
yes/noboolean 或 java.lang.BooleanCHAR(1) (‘Y’ or ‘N’)
true/falseboolean 或 java.lang.BooleanCHAR(1) (‘T’ or ‘F’)
日期和时间类型
映射类型Java 类型ANSI SQL 类型
datejava.util.Date 或 java.sql.DateDATE
timejava.util.Date 或 java.sql.TimeTIME
timestampjava.util.Date 或 java.sql.TimestampTIMESTAMP
calendarjava.util.CalendarTIMESTAMP
calendar_datejava.util.CalendarDATE
二进制和大型数据类型
映射类型Java 类型ANSI SQL 类型
binarybyte[]VARBINARY (or BLOB)
textjava.lang.StringCLOB
serializableany Java class that implements java.io.SerializableVARBINARY (or BLOB)
clobjava.sql.ClobCLOB
blobjava.sql.BlobBLOB
JDK相关类型
映射类型Java 类型ANSI SQL 类型
classjava.lang.ClassVARCHAR
localejava.util.LocaleVARCHAR
timezonejava.util.TimeZoneVARCHAR
currencyjava.util.CurrencyVARCHAR

对应的sql:

create table user
(
    id   int auto_increment primary key,
    name varchar(20)      not null,
    pass varchar(30)      not null,
    sex  char default 'M' not null,
    constraint name unique (name)
)charset = utf8;

映射注解

使用hibernate的注解比使用xml映射文件的方式方便,而且具有良好的可观性。特别是在spring推崇的去文档化,尽量减少对xml这类文档的依赖,采用编程的方式解决配置等问题。

@Entity

@Entity用于对POJO实体类注解,以明确这是一个实体类。

@Entity
public class User implements Serializable {
    ...
}
@Table

@Table用于注解实体对应的表。

@Entity
@Table(name = "user")
public class User implements Serializable {
    ...
}
@Id

@Id用于对primark key主键属性的注解。

@Entity
@Table(name = "user")
public class User implements Serializable {
    @Id
    private Integer id;
    ...
}
@GeneratedValue

@GeneratedValue注解指示了属性值的生成策略,通常选用GenerationType.AUTO即可。

@Entity
@Table(name = "user")
public class User implements Serializable {
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    ...
}

GenerationType.AUTO : 自动选择

GenerationType.SEQUENCE : 按顺序自增

GenerationType.Table : 按值表的方式,由hibernate生成一个主键表

GenerationType.IDENTITY : 保持与entity一致

@Column

@Column注解用于映射实体的属性和表的字段的关系。

@Entity
@Table(name = "user")
public class User implements Serializable {
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

    @Column(name = "name", nullable = false, unique = true)
    private String name;
    ...
}
@DynamicUpdate和@DynamicInsert

指示在对象的更新与插入时,过滤null值的属性。

@Entity
@Table(name = "user")
@DynamicUpdate
@DynamicInsert
public class User implements Serializable {
    ...
}
实体关系(表间关系)

对于关系模式的表间关系有一对一、一对多、多对多的关系,可以通过注解的方式来完成实体间的关系。

注意:在完成对象关系时,有关系“提供方”和“使用方”。关系的提供方要维护两者关系,负责对数据的操作。

对于一对一和多对多,维护方按照实际对象关系确定即可,对于一对多的方式,维护方只能为一的那个对象

@OneToOne (一对一)

现在有User和Role两个类,假设一个用户只能有一个角色,一个角色只能属于一个用户。

对于User类:

@Entity
@Table(name = "user")
@DynamicUpdate
@DynamicInsert
public class User implements Serializable {
    ...
    @OneToOne
    @JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false)
    private Role role;
    ...
}

对于Role类:

@Entity
@Table(name = "role")
@DynamicInsert
@DynamicUpdate
public class Role implements Serializable {
    ...
    @OneToOne(mappedBy = "role")
    private User user;
    ...
}
@OneToMany (一对多)

假设一个用户有多个角色,一个角色只能属于一个用户。

对于User类:

@Entity
@Table(name = "user")
@DynamicUpdate
@DynamicInsert
public class User implements Serializable {
    ...
    @OneToMany(mappedBy = "user")
    private Set<Role> roles = new HashSet<>();
    ...
}

对于Role类:

@Entity
@Table(name = "role")
@DynamicInsert
@DynamicUpdate
public class Role implements Serializable {
    ...
    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
    private User user;
    ...
}
@ManyToMany (多对多)

假设一个用户可以有多个角色 ,一个角色可以属于多个用户。(注意:多对多的情况需要准备中间表。

根据实际分析,由User来作关系的维护者。

对于User类:

@Entity
@Table(name = "user")
@DynamicUpdate
@DynamicInsert
public class User implements Serializable {
    ...
    // @JoinColumns定义了中间表的信息
    @ManyToMany(targetEntity = Role.class)
    @JoinTable(name = "user_role", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)}
            , inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id", nullable = false)})
    private Set<Role> roles = new HashSet<>();
    ...
}

对于Role类:

@Entity
@Table(name = "role")
@DynamicInsert
@DynamicUpdate
public class Role implements Serializable {
    ...
    @ManyToMany(mappedBy = "roles")
    private Set<User> users = new HashSet<>();
    ...
}

创建会话(Session)

创建会话首先需要SessionFactory,可以通过Configuration读取hibernate的配置文件,或者通过setProperty的方式设定hibernate的属性。

SessionFactory

  1. 读取项目目录下的默认配置文件(hibernate.cfg.xml)

    // 以下语句将使用默认的hibernate.cfg.xml配置文件
    private final static SessionFactory FACOTRY = new Configuration().configure().buildSessionFactory();
    
  2. 指定配置文件

    // 指定配置文件,只需要在invoke configure方法时传入配置文件信息
    // configure方法原型如下:
    configure();		// 读取hibernate.cfg.xml
    // 以下自定义配置文件名
    configure(String resource);
    configure(URL url);
    configure(File configFile);
    
  3. 通过编程方式设定
    setProperty方法:

    // 一个简单的例子如下:
            new Configuration().configure()
                    .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect")
                    .setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver")
                    .setProperty("hibernate.connection.url", "jdbc:mysql://localhost:3306/hibernate_study?serverTimezone=UTC")
                    .setProperty("hibernate.connection.username", "dev").setProperty("hibernate.connection.password", "123456")
                    .buildSessionFactory();
    

    setProperties方法:

    // 实例化Properties对象
    Properties prs = new Properties();
    prs.put("hibernate.dialect", "org.hibernate.dialect.MysqlDialect");
    prs.put("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver");
    ...
    // 设置配置
    new Configuration().configure().setProperties(prs);
    

打开会话

当获得SeesionFactory后,就可以通过factory来开启Session会话。

// 开户一个会话
Session session = FACTORY.openSession();

coding...

// 使用完成后关闭会话
session.close();
// 也可以通过factory关闭所有已打开的会话,这是不安全的
//FACTORY.close();

HQL (hibernate query language)

HQL的语法和T-SQL的语法大致相同,不过HQL是对对象进行操作(对象已经和相应的表进行映射 ),而T-SQL直接针对的是表。使用HQL的INSERT语句时需要注意,INSERT语句不允许直接插入新的对象数据,但是可以将一个对象的信息插入另一个对象(与SELECT语句结合使用)。

SELECT语句

// 如果要查询某个对象的所有属性,可以省略SELECT
// 注意这里的User是实体,而不是表名
String hql = "FROM User";		// 等效于 "SELECT * FROM User"

// 创建查询
session.createQuery(hql);		// => 返回Query对象

// 可以将User.class传入
session.createQuery(hql, User.class);	// => 返回Query<User>对象

// 最后可以通过list()方法来获取结果集
session.createQuery(hql, User.class).list();		// getResultsList()调用的是list()方法

// 只需要获取一个结果,可以使用getSingleResult()方法,直接返回一个User对象
session.createQuery(hql, User.class).getSingleResult();

查询单个属性或者多个属性时,必要的时候需要将结果存入map中,方便对数据进行读取。

// 只查询id属性
String hql = "SELECT id FROM User";
Query query = Session.createQuery(hql);
// 获取结果集
List list = query.list();		// 返回的是含有属性值的列表
    
// 可以转换为map
List list1 = query.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP).list();  // 返回含有map的list列表

// 对于多个属性的查询,以上的转换是非常必要的,否则只能得到Object对象
// 注意:hibernate的很多方法已经弃用,包括setResultTransformer方法。
// 实际上对于简单的CRUD,可以通过hibernate封装的find、save、saveOrUpdate、delete方法来操作实体。
String hql = "SELECT id, name FROM User";
Query query1 = session.createQuery(hql);
List list2 = query1.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP).list();

动态参数

曾几何时,使用jdbc的时候,使用"?“作为占位符。现在使用hibernate绑定参数变得更加方便,可以使用”:“的方式,或者使用jpa的占位格式,”?"。

// 绑定参数
String hql = "UPDATE User Set name = :name, pass = :pass WHERE id = :id";

// 对于非查询操作,记得开启事务
Transaction tx = sexxion.beginTransaction();
Query query = session.createQuery(hql, User.class);
query.setParameter("name", "newName");
query.setParameter("pass", "newPass");
query.setParameter("id", 1);
System.out.println(query.executeUpdate());

// 提交当前事务
tx.commit();


// 使用jpa的占位符格式
// jpa的格式的问号加上参数索引的方式
// 即 "?<parameter-index>"
// 注意:索引下标是从0开始的
String hql = "FROM User WHERE id = ?0";
Query query = session.createQuery(hql, User.class);
query.setParameter(0, 1);		// fistr param is index
System.out.println(query.list());

DELETE语句

在实际的测试中,对于非查询的语句需要开启事务,否则将会出现异常。其次与查询不同的是需要调用==executeUpdate()==方法来执行非查询操作。

String hql = "DELETE FROM User WHERE id = 1";

// 开启事务
Transaction tx = session.beginTransaction();
try {
    // 执行delete
    int res = session.createQuery(hql).executeUpdate();
    // 提交事务
    tx.commit();
}catch (HibernateException e) {
    e.printStackTrace();
    tx.rollback(); // 回滚
}finally {
    // 关闭session
    session.close();
}
return -1;

UPDATE语句

String hql = "UPDATE User SET name = 'llzero', pass = '123456' WHERE id = 1";

// 开启事务
Transaction tx = session.beginTransaction();
try {
    int res = session.createQuery(hql).executeUpdate();
    // 提交事务
    tx.commit();
}catch (HibernateException e) {
    e.printStackTrace();
    tx.rollback(); // 回滚
}finally {
    // 关闭session
    session.close();
}
return -1;

INSERT语句

// 注意:INSERT不能用于直接插入对象,只有用于复制对象
// 不像T-SQL一样,有VALUES关键字
// 复制id为1的对象的pass和sex属性,并产生一个name为'llZero'的新对象
String hql = "INSERT INTO User(name, pass, sex) SELECT 'llZero', pass, sex FROM User WHERE id = 1";
...

WHERE 子句

WHERE子句能够对查询的数据进行filter,支持使用ANDOR关键字来组合逻辑,其中表达式符号有"="、"!="、">"、">="、"<"、"<=“以及”()"等。

String hql = "FROM User WHERE id = 1 OR id = 3 OR id >= 10";

AS关键字

AS可以为表或者某一属性取别名。

String hql = "SELECT U.id AS uid, U.name AS uname FROM User AS U";

ORDER BY 排序

对于排序,同T-SQL一样,使用ORDER BY关键字,多个参与排序的属性使用“,”隔开。

DESC : 降序

ASC (默认): 升序

String hql = "FROM User ORDER BY name, id DESC";

GROUP BY 分组

hql的分组同T-SQL一致,多个参与分组的属性采用半角逗号隔开。

String hql = "FROM User GROUP BY name, pass";

分页查询

hibernate的分页查询通过调用两个方法来实现,其效果和LIMIT关键字相同。

setFirstResult(int resultPoint) : 开始读取的位置

setMaxResults(int num) : 每次最大多少条数据

String hql = "FROM User";
// 以下语句从第四个对象开始读取,最多返回5个对象
Query query = session.createQuery(hql, User.class).setFirstResult(3).setMaxRusults(5).list();

聚合函数

S.N.方法描述
1avg(property name)属性的平均值
2count(property name or *)属性在结果中出现的次数
3max(property name)属性值的最大值
4min(property name)属性值的最小值
5sum(property name)属性值的总和
// 使用count的例子
String hql = "SELECT count(pass) AS pCount FROM User Group By pass";

标准查询

hibernate的标查询使用到的Class是Criteria,其实质是将hql进行分拆组合

Criteria cr = session.createCriteria(User.class);
System.out.println(cr.list());

// 对标准的限制
// 使用add方法来添加对标准的限制
// Restrictions中定义相关限制
cr.add(Restrictions.eq("id", 3));
System.out.println(cr.list());
cr.add(Restrictions.isNull("id"));
cr.add(Restrictions.isNotNull("id"));
cr.add(Restrictions.isEmpty("id");
cr.add(Restrictions.isNotEmpty("id"));
cr.add(Restrictions.ge("id", 10));
cr.add(Restrictions.le("id", 20));
cr.add(Restrictions.gt("id", 30));
cr.add(Restrictions.lt("id", 40)));

// 模糊查询,使用"%"或"_"
cr.add(Restrictions.like("id", "5%"));
// 值区间
cr.add(Restrictions.between("id", 2, 5));

// AND或OR条件
Criterion cr1 = Restrictions.eq("id", 3);
Criterion cr2 = Restrictions.eq("pass", "123456");
System.out.println(cr.add(Restrictions.and(cr1, cr2)).list());
System.out.println(cr.add(Restrictions.or(cr1, cr2)).list());

// 分页
System.out.println(cr.setFirstResult(2).setMaxResults(2).list());

// 排序,使用Order类
// 注意addOrder方法
System.out.println(cr.addOrder(Order.desc("id")).list());

// 预测与聚合
// Projections类中的方法有求最值、平均值等的方法
System.out.println(cr.setProjection(Projections.avg("id")));
System.out.println(cr.setProjection(Projections.max("id")).list());

原生查询

hibernate除了支持HQL与标准查询以外,同样也可以使用原生的SQL语句进行查询。但是并不建议那么做,因为不同的DBMS的语法存在出入,可能会为移植带来不便。

String sql = "SELECT * FROM user";

NativeQuery sqlQuery = session.createSQLQuery(sql);
System.out.println(sqlQuery.list());

// 标量查询
String sql = "SELECT id,name FROM user";
NativeQuery sqlQuery = session.createSQLQuery(sql);
// 把结果转换为map对象
Query query = sqlQuery.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP);
System.out.println(query.list());

// 实体查询
// 通过SqlQuery的addEntity(O)方法添加实体映射数据
String sql = "SELECT * FROM user";
SQLQuery sqlQuery = session.createSQLQuery(sql);
// 绑定的实体
sqlQuery.addEntity("cn.llzero.entity.User");
sqlQuery.addEntity(User.class);
System.out.println(sqlQuery.list());

// 动态参数
// 可以参考HQL
String sql = "SELECT * FROM user WHERE id = :id";
SQLQuery sqlQuery = session.createSQLQuery(sql);
sqlQuery.addEntity("cn.llzero.entity.User");
sqlQuery.setParameter("id", 3);
System.out.println(sqlQuery.getSingleResult());

interceptor 拦截器

实现hibernate的拦截器有两种方式,一种是实现Interceptor接口,还有一种就是继承EmptyInterceptor空拦截器选择性的重写自己想要实现的方法。

Interceptor的定义如下:

public interface Interceptor {
    boolean onLoad(Object var1, Serializable var2, Object[] var3, String[] var4, Type[] var5) throws CallbackException;

    boolean onFlushDirty(Object var1, Serializable var2, Object[] var3, Object[] var4, String[] var5, Type[] var6) throws CallbackException;

    boolean onSave(Object var1, Serializable var2, Object[] var3, String[] var4, Type[] var5) throws CallbackException;

    void onDelete(Object var1, Serializable var2, Object[] var3, String[] var4, Type[] var5) throws CallbackException;

    void onCollectionRecreate(Object var1, Serializable var2) throws CallbackException;

    void onCollectionRemove(Object var1, Serializable var2) throws CallbackException;

    void onCollectionUpdate(Object var1, Serializable var2) throws CallbackException;

    void preFlush(Iterator var1) throws CallbackException;

    void postFlush(Iterator var1) throws CallbackException;

    Boolean isTransient(Object var1);

    int[] findDirty(Object var1, Serializable var2, Object[] var3, Object[] var4, String[] var5, Type[] var6);

    Object instantiate(String var1, EntityMode var2, Serializable var3) throws CallbackException;

    String getEntityName(Object var1) throws CallbackException;

    Object getEntity(String var1, Serializable var2) throws CallbackException;

    void afterTransactionBegin(Transaction var1);

    void beforeTransactionCompletion(Transaction var1);

    void afterTransactionCompletion(Transaction var1);

    /** @deprecated */
    @Deprecated
    String onPrepareStatement(String var1);
}

编写HibernateInterceptor类,并继承EmptyInterceptor重写方法。

public class HibernateInterceptor extends EmptyInterceptor {
    @Override
    public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        System.out.println("on delete!");
        super.onDelete(entity, id, state, propertyNames, types);
    }

    @Override
    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
        System.out.println("on flush dirty");
        return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);
    }

    @Override
    public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        System.out.println("on load");
        return super.onLoad(entity, id, state, propertyNames, types);
    }

    @Override
    public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
        System.out.println("on save");
        return super.onSave(entity, id, state, propertyNames, types);
    }

    @Override
    public void postFlush(Iterator entities) {
        System.out.println("post flush");
        super.postFlush(entities);
    }

    @Override
    public void preFlush(Iterator entities) {
        System.out.println("pre flush");
        super.preFlush(entities);
    }

    @Override
    public Boolean isTransient(Object entity) {
        System.out.println("isTransient");
        return super.isTransient(entity);
    }

    @Override
    public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
        System.out.println("instantiate");
        return super.instantiate(entityName, entityMode, id);
    }

    @Override
    public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {
        System.out.println("findDirty");
        return super.findDirty(entity, id, currentState, previousState, propertyNames, types);
    }

    @Override
    public String getEntityName(Object object) {
        System.out.println("getEntityName");
        return super.getEntityName(object);
    }

    @Override
    public Object getEntity(String entityName, Serializable id) {
        System.out.println("getEntity");
        return super.getEntity(entityName, id);
    }

    @Override
    public void afterTransactionBegin(Transaction tx) {
        System.out.println("afterTransactionBegin");
        super.afterTransactionBegin(tx);
    }

    @Override
    public void afterTransactionCompletion(Transaction tx) {
        System.out.println("afterTransactionCompletion");
        super.afterTransactionCompletion(tx);
    }

    @Override
    public void beforeTransactionCompletion(Transaction tx) {
        System.out.println("beforeTransactionCompletion");
        super.beforeTransactionCompletion(tx);
    }

    @Override
    public String onPrepareStatement(String sql) {
        System.out.println("onPrepareStatement");
        return super.onPrepareStatement(sql);
    }

    @Override
    public void onCollectionRemove(Object collection, Serializable key) throws CallbackException {
        System.out.println("onCollectionRemove");
        super.onCollectionRemove(collection, key);
    }

    @Override
    public void onCollectionRecreate(Object collection, Serializable key) throws CallbackException {
        System.out.println("onCollectionRecreate");
        super.onCollectionRecreate(collection, key);
    }

    @Override
    public void onCollectionUpdate(Object collection, Serializable key) throws CallbackException {
        System.out.println("onCollectionUpdate");
        super.onCollectionUpdate(collection, key);
    }
}

拦截器常用方法解释

findDirty()
这个方法在当 flush() 方法在一个 Session 对象上被调用时被调用。
instantiate()
这个方法在一个持续的类被实例化时被调用。
isUnsaved()
这个方法在当一个对象被传到 saveOrUpdate() 方法时被调用。
onDelete()
这个方法在一个对象被删除前被调用。
onFlushDirty()
这个方法在当 Hibernate 探测到一个对象在一次 flush(例如,更新操作)中是脏的(例如,被修改)时被调用。
onLoad()
这个方法在一个对象被初始化之前被调用。
onSave()
这个方法在一个对象被保存前被调用。
postFlush()
这个方法在一次 flush 已经发生并且一个对象已经在内存中被更新后被调用。
preFlush()
这个方法在一次 flush 前被调用。

使用自定义拦截器

// 对于所有的会话
// 通过setInterceptor方法指定拦截器
private final static SessionFactory FACTORY = new Configuration().configure()
            .setInterceptor(new HibernateInterceptor()).addAnnotatedClass(User.class)
            .buildSessionFactory();

hibernate缓存

使用 session.flush()session.clear() 可以同步缓存和清理内存中的缓存,hibernate默认使用的CacheProvider是EHCache。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 对于tortoise-orm与sqlalchemy的使用,Tortoise ORM 用于快速构建 ORM 层,可以让你使用 Python 代码来实现数据库操作,而 SQLAlchemy 则是一个 Python 数据库访问库,可以用于访问不同的关系数据库,包括 Postgres、MySQL、Oracle 等。 ### 回答2: Tortoise-ORM和SQLAlchemy都是Python编程中常用的对象关系映射(ORM)工具,用于简化与数据库的交互。下面是关于这两个工具的使用的一些说明: 1. Tortoise-ORM是一个基于异步操作的ORM框架,使用Python 3.7+版本。它支持多种数据库后端,如MySQL、PostgreSQL和SQLite等。Tortoise-ORM提供了通过定义模型类来映射数据库表,并自动创建表、插入、查询和更新数据等操作的功能。它还支持事务操作和异步查询等高级特性。 2. SQLAlchemy是一个功能强大的Python ORM库,支持多个数据库后端,如MySQL、PostgreSQL、SQLite和Oracle等。它提供了两种不同的查询语言,一种是SQL表达式语言,另一种是ORM模型类的形式。使用SQLAlchemy,可以通过定义模型类来映射数据库表,实现CRUD操作,并支持复杂的查询和多表联接等操作。 Tortoise-ORM和SQLAlchemy都有各自的特点和优势,适用于不同的场景和需求。Tortoise-ORM是一个轻量级的ORM框架,适用于异步编程和小型项目,它提供了更简单和直观的API,并简化了与异步框架的集成。SQLAlchemy则更加成熟和强大,适用于复杂的数据操作和大型项目。它提供了更多的灵活性和可定制性,使开发者能够更细粒度地控制数据库操作。 总体来说,无论是Tortoise-ORM还是SQLAlchemy,它们都能够简化与数据库的交互,提高开发效率。选择哪个工具取决于具体项目需求和个人偏好。 ### 回答3: Tortoise-ORM和SQLAlchemy是两个Python中的ORM(对象关系映射)库,用于管理和操作关系数据库。 Tortoise-ORM是一个异步IO框架下的ORM库,专门针对Tortoise-ORM的异步IO特性进行了优化。它提供了简单易用的API,可以使用Python的异步IO库asyncio进行数据库操作。Tortoise-ORM支持多种数据库后端,包括SQLite、MySQL和PostgreSQL等。它支持自动生成数据库模式、提供了ORM模型定义和查询API,并且可以更加高效地进行关系型数据库的操作。 SQLAlchemy是一个功能强大的ORM库,它也支持多种关系型数据库后端。SQLAlchemy提供了一种SQL表达式语言(SQL Expression Language),使得开发者可以使用Python代码来生成复杂的SQL查询语句,这些查询语句可以直接映射到数据库进行运行。SQLAlchemy还提供了ORM映射配置工具,可以方便地将数据库表映射到Python类,并且支持多种查询方式和事务操作。 Tortoise-ORM与SQLAlchemy在功能和用法上有一些区别。Tortoise-ORM更加适合异步IO的应用程序,它的API设计更加简单干净,操作数据库更加高效。相比之下,SQLAlchemy提供了更多的功能和灵活性,但在性能上相对较差。 总而言之,Tortoise-ORM和SQLAlchemy都是非常优秀的ORM库,可以用于开发各种类型的关系型数据库应用程序。开发者可以根据自己的需求和偏好选择合适的库进行使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值