文章目錄
-
- 前言
- 環境說明
- 配置過程
-
- 1.資料庫建立
- 2.項目搭建
- 3.配置hibernate.cfg.xml
- 4.映射關系
-
- 4.1 xml映射方式
- 4.2 注解映射方式
- 5.建立SessionFactory
- 6. 單元測試用例
- 總結
前言
為什麼突然想起寫一個hibernate的簡單配置教程呢,因為最近兩年都沒怎麼和資料庫打交道,而以前對這些架構的配置都是知其然不知其是以然,是以就想把以前簡單用過的的hibernate拿出來再熟練一下,加深印象,是以借此篇部落格,幫助他人的同時順便為以後使用留點資料,同時養成寫部落格的好習慣。
ps:後面有時間,可能就把整個測試Demo項目傳到GitHup上面去(其實代碼都給出來了)
環境說明
Mysql(windows10)5.7.26、hibernate5.3.10、druid1.1.19、c3p05.3.10
配置過程
1.資料庫建立
建立如圖所示:
2.項目搭建
此次教程基于mysql5.7.26,hibernate5.3.10,連接配接池使用了druid和c3p0(二選一),并沒有使用spring。為了導包友善,先建一個基于maven的web項目,然後在pom檔案中增加以下引用。
<properties>
<!-- 版本管理 -->
<hibernate.version>5.3.10.Final</hibernate.version>
<c3p0.version>5.3.10.Final</c3p0.version>
<mysql.version>8.0.16</mysql.version>
<hibernate.version>5.3.10.Final</hibernate.version>
<druid.version>1.1.19</druid.version>
<lombok.version>1.18.8</lombok.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- c3p0連接配接池 -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- 阿裡druid連接配接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>${lombok.version}</version>
</dependency>
</dependencies>
先看一下工程結構
3.配置hibernate.cfg.xml
本文主要側重于講解注解配置的方式(
推薦
),使用xml配置的方式僅提供簡單配置以供參考。
druid連接配接池的配置:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--dataSource for Druid start -->
<property name="driverClassName">com.mysql.cj.jdbc.Driver</property>
<property name="url">jdbc:mysql://localhost:3306/hibernatetest?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false</property>
<property name="username">test</property>
<property name="password">123456</property>
<property name="filters">stat</property>
<property name="initialSize">1</property>
<property name="maxActive">20</property>
<property name="minIdle">1</property>
<property name="maxWait">60000</property>
<property name="timeBetweenEvictionRunsMillis">60000</property>
<property name="minEvictableIdleTimeMillis">300000</property>
<property name="validationQuery">SELECT 1</property>
<property name="testWhileIdle">true</property>
<property name="testOnBorrow">false</property>
<property name="testOnReturn">false</property>
<property name="poolPreparedStatements">true</property>
<property name="maxOpenPreparedStatements">20</property>
<property name="maxPoolPreparedStatementPerConnectionSize">200</property>
<property name="asyncInit">true</property>
<!--dataSource for Druid end -->
<!--指定資料庫名,mysql低版本曾用hibernate.default_schema表示資料庫名 -->
<property name="hibernate.default_catalog">hibernatetest</property>
<!-- 指定資料庫方言 -->
<!--該方言預設使用MyISAM引擎 -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--InnoDB -->
<!--<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> -->
<!-- 顯示Hibernate持久化操作所生成的SQL -->
<property name="show_sql">true</property>
<!-- 将SQL腳本進行格式化後再輸出 -->
<property name="hibernate.format_sql">true</property>
<!--自定義ConnectionProvider的類名, 此類用來向Hibernate提供JDBC連接配接. -->
<property name="hibernate.connection.provider_class">com.alibaba.druid.support.hibernate.DruidConnectionProvider</property>
<!-- 測試環境使用create/create-drop 正式環境使用update/validate -->
<property name="hbm2ddl.auto">update</property>
<!-- 使用JDBC連接配接檢查資料庫中繼資料,據說使用連接配接池這裡設定為false,但是整個測試過程中true或者false都挺正常,但是以防萬一還是加上吧 -->
<property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
<!-- 禁用二級緩存 -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- 設定事務隔離級别 1 可讀未送出 2可讀已送出 4可重複讀 8串行化 -->
<property name="hibernate.connection.isolation">4</property>
<!--羅列所有持久化類的類名 -->
<mapping class="com.hibernate.demo.entity.pojo.School" />
<mapping class="com.hibernate.demo.entity.pojo.Teacher" />
<!-- 用來關聯hbm配置檔案 -->
<mapping resource="com/hibernate/demo/entity/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
c3p0連接配接池的配置:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<!--hibernate.可以省略,hibernate會做判斷,如 hibernate.c3p0.max_size可寫成c3p0.max_size -->
<session-factory>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernatetest?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false</property>
<property name="connection.username">test</property>
<property name="connection.password">123456</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- 指定連接配接池裡最大連接配接數 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 指定連接配接池裡最小連接配接數 -->
<property name="hibernate.c3p0.min_size">1</property>
<!-- 指定連接配接池裡連接配接的逾時時長 -->
<property name="hibernate.c3p0.timeout">5000</property>
<!-- 指定連接配接池裡最大緩存多少個Statement對象 -->
<property name="hibernate.c3p0.max_statements">100</property>
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<!--指定資料庫名,mysql低版本曾用hibernate.default_schema表示資料庫名 -->
<property name="hibernate.default_catalog">hibernatetest</property>
<!-- 指定資料庫方言 -->
<!--該方言預設使用MyISAM引擎-->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!--InnoDB-->
<!--<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>-->
<!-- 顯示Hibernate持久化操作所生成的SQL -->
<property name="show_sql">true</property>
<!-- 将SQL腳本進行格式化後再輸出 -->
<property name="hibernate.format_sql">true</property>
<!-- 測試環境使用create/create-drop 正式環境使用update/validate -->
<property name="hbm2ddl.auto">update</property>
<!-- 使用JDBC連接配接檢查資料庫中繼資料,據說使用連接配接池這裡設定為false,但是整個測試過程中true或者false都挺正常,但是以防萬一還是加上吧 -->
<property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
<!-- 禁用二級緩存 -->
<property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property>
<!-- 設定事務隔離級别 1 可讀未送出 2可讀已送出 4可重複讀 8串行化 -->
<property name="hibernate.connection.isolation">4</property>
<!--羅列所有持久化類的類名 -->
<mapping class="com.hibernate.demo.entity.pojo.School"/>
<mapping class="com.hibernate.demo.entity.pojo.Teacher"/>
<!-- 用來關聯hbm配置檔案 -->
<mapping resource="com/hibernate/demo/entity/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
在這裡不得不說一下方言的選擇,測試過程中建表報錯
Specified key was too long; max key length is 1000 bytes
,錯誤的原因是因為我主鍵指定長度
id varchar(300) not null
太長了,經查詢資料得知:
因為我建立資料路時指定的是
utf8mb4
,utf8mb4字元每個字元最多四個位元組,是以300*4就超出了MyISAM引擎對主鍵長度限制,是以這裡将MyISAM改為了InnoDB:
如果想要使用InnoDB引擎,有兩種方式:
方式一:
在hibernate.cfg.xml中指定方言為
org.hibernate.dialect.MySQL5InnoDBDialect
方式二:如果堅持使用
org.hibernate.dialect.MySQL5Dialect
方言,該方言預設使用MyISAM引擎,可以在src/resources/hibernate.properties 中增加以下屬性指定使用InnoDB引擎(經過測試)
hibernate.dialect.storage_engine=innodb
4.映射關系
hibernate 有兩種映射方式分别是注解(推薦)和xml,這裡我都配置一下,當然xml的僅提供一個入門級的配置,重點在注解配置方式,後面提供的單元測試用例也主要是針對注解類的。
4.1 xml映射方式
User 類
package com.hibernate.demo.entity;
import java.util.Date;
import javax.persistence.Entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
private Integer userId;
private String firstName;
private String lastName;
private String sex;
private Date birthday;
private String telNum;
private Date createTime;
}
映射檔案必須在hibernate.cfg.xml配置才起作用,如下:
<mapping resource="com/hibernate/demo/entity/User.hbm.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 package="com.hibernate.demo.entity">
<!-- name代表的是實體類名,table代表的是表名 -->
<class name="User" table="user">
<meta attribute="class-description">
This class contains the user detail.
</meta>
<id name="userId" type="int" column="user_id">
<generator class="native"/>
<!-- 自增長主鍵不同資料庫有不同類型的自增長類型,有需要可以百度到答案的
<generator class="identity"></generator> -->
</id>
<!-- 非主鍵映射關系,注意類型并不是單純的java類型也不是資料庫類型,而是一種中間類型,注意大小寫特别是String在這裡開頭要小寫 -->
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="sex" column="sex" type="string"/>
<property name="birthday" column="birthday" type="date"/>
<property name="telNum" column="telNum" type="string"/>
<property name="createTime" column="createTime" type="timestamp"/>
</class>
</hibernate-mapping>
4.2 注解映射方式
注解的話也是需要在hibernate.cfg.xml中指定。如下:
<mapping class="com.hibernate.demo.entity.pojo.Teacher"/>
不需要使用xml,相當的友善,下文會給出示例,實體類字段并沒什麼業務含義,單純的隻是嘗試使用不同的注解,廢話不多說直接上代碼。
BaseEntity
package com.hibernate.demo.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Version;
@MappedSuperclass
public class BaseEntity implements java.io.Serializable {
/**
* <序列号>
*/
private static final long serialVersionUID = 7544096556094410178L;
// @Temporal(TemporalType.DATE)(精确到年月日)
// @Temporal(TemporalType.TIME)(精确到時分秒)
// @Temporal(TemporalType.TIMESTAMP)(預設年月日時分秒)
// 記錄建立時間
@Column(name = "created_time")
@Temporal(TemporalType.TIMESTAMP)
private Date createdTime;
// 記錄更新時間
@Column(name = "updated_time")
@Temporal(TemporalType.TIMESTAMP)
private Date updatedTime;
// 描述更新内容
@Column(name = "body")
private String description;
//注解用于支援樂觀鎖版本控制。
@Version
private Integer version;
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
public Date getUpdatedTime() {
return updatedTime;
}
public void setUpdatedTime(Date updatedTime) {
this.updatedTime = updatedTime;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
School
package com.hibernate.demo.entity.pojo;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.hibernate.demo.entity.BaseEntity;
@Entity // 定義了一個實體
@Table(name = "school")
public class School extends BaseEntity{
private static final long serialVersionUID = 1653242906575651690L;
// TABLE:使用一個特定的資料庫表格來儲存主鍵。
// SEQUENCE:根據底層資料庫的序列來生成主鍵,條件是資料庫支援序列。
// IDENTITY:主鍵由資料庫自動生成(主要是自動增長型)
// AUTO:主鍵由程式控制。
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer schoolId;
@Column(length = 30, nullable = false)
private String schoolName;
private Long ranking; // 排名
// 關聯關系由Teacher類維護
// 延遲加載
@OneToMany(mappedBy="schl", fetch=FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = Teacher.class)
private Set<Teacher> teachers;
public Integer getSchoolId() {
return schoolId;
}
public void setSchoolId(Integer schoolId) {
this.schoolId = schoolId;
}
public String getSchoolName() {
return schoolName;
}
public void setSchoolName(String schoolName) {
this.schoolName = schoolName;
}
public Long getRanking() {
return ranking;
}
public void setRanking(Long ranking) {
this.ranking = ranking;
}
public Set<Teacher> getTeachers() {
return teachers;
}
public void setTeachers(Set<Teacher> teachers) {
this.teachers = teachers;
}
public School() {
super();
}
public School(Integer schoolId, String schoolName, Long ranking, Set<Teacher> teachers) {
super();
this.schoolId = schoolId;
this.schoolName = schoolName;
this.ranking = ranking;
this.teachers = teachers;
}
@Override
public String toString() {
return "School [schoolId=" + schoolId + ", schoolName=" + schoolName + ", ranking=" + ranking + "]";
}
}
Teacher
package com.hibernate.demo.entity.pojo;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.BatchSize;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import com.hibernate.demo.entity.BaseEntity;
@Entity
@Table(name = "teacher")
public class Teacher extends BaseEntity {
private static final long serialVersionUID = -6858635556382148936L;
// 生成UUID的主鍵生成政策
@Id
@GenericGenerator(name = "idGenerator", strategy = "org.hibernate.id.UUIDGenerator")
@GeneratedValue(generator = "idGenerator")
// 定義列名
// insertable表示該字段是否可以出現在insert語句中,預設值為true,通常為主鍵、時間戳等字段的值設定為false。因為它們的值都是自動生成的,不需要在insert時插入;
@Column(name = "t_id",insertable=false)
private String teacherId;
@Type(type = "string")
private String name;
@Type(type = "string")
private String sex;
/**
* fetch: 擷取政策,當以session.get()方法擷取資料庫對象時:
* FetchType.LAZY為懶加載,會在第一次使用該屬性(如調用getAge()方法)時才擷取。
* FetchType.EAGER為即時加載。
* optional:表示目前屬性是否可選,預設為true,如果為false,則在持久化到資料庫時,如果此屬性為null,則會失敗
*/
@JoinColumn(name = "s_id")
// @ManyToOne(fetch = FetchType.EAGER, optional = true,targetEntity = School.class,cascade = CascadeType.ALL)
@ManyToOne(fetch = FetchType.EAGER, optional = true,targetEntity = School.class,cascade = CascadeType.MERGE)
@BatchSize(size = 50)
private School schl;
// 現在這個屬性不想生成在表中
@Transient
private String msg;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public School getSchl() {
return schl;
}
public void setSchl(School schl) {
this.schl = schl;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Teacher() {
super();
}
public Teacher(String teacherId, String name, String sex, School schl, String msg) {
super();
this.teacherId = teacherId;
this.name = name;
this.sex = sex;
this.schl = schl;
this.msg = msg;
}
/**
*toString 注意不要輸出學校,否則互相引用容易造成棧溢出,此處兩個類都隻輸出普通屬性
*/
@Override
public String toString() {
return "Teacher [teacherId=" + teacherId + ", name=" + name + ", sex=" + sex + ", msg=" + msg + "]";
}
}
5.建立SessionFactory
package com.hibernate.demo.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
public class HibernateUtils {
private static final SessionFactory sessionFactory;
/* hibernate4.3 棄用org.hibernate.service.ServiceRegistryBuilder類 */
static {
try {
/* hibernate5.X 擷取factory方式 */
// 方式一
// sessionFactory = new Configuration().configure().buildSessionFactory();
// 方式二
// 不指定配置檔案的檔案名會預設讀取hibernate.cfg.xml的内容
// c3p0
// StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure("hibernate.cfg_c3p0.xml").build();
// 預設hibernate.cfg.xml druid
StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().configure().build();
Metadata metadata = new MetadataSources(standardRegistry).getMetadataBuilder()
.applyImplicitNamingStrategy(ImplicitNamingStrategyComponentPathImpl.INSTANCE).build();
// 最後由這個metadata使用建構出sessionFactory
sessionFactory = metadata.getSessionFactoryBuilder().build();
/**
* 下面的來源于網絡,未經測試,僅供參考
*/
/*hibernate4.3之後版本 擷取factory方式 */
// // 第一步 建立服務注冊對象
// ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
// .applySettings(configuration.getProperties()).build();
// // 第二步 建立會話工廠對象
// sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}catch (Throwable ex) {
ex.printStackTrace();
// Log exception!
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession() throws HibernateException {
return sessionFactory.openSession();
}
}
6. 單元測試用例
package com.hibernate.demo.util;
import static org.junit.Assert.assertNotNull;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Root;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.hibernate.demo.entity.pojo.School;
import com.hibernate.demo.entity.pojo.Teacher;
class HibernateUtilsTest {
private static Session session;
private static SimpleDateFormat sdf;
@BeforeAll
static void setUpBeforeClass() throws Exception {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
session = HibernateUtils.getSession();
}
@AfterAll
static void tearDownAfterClass() throws Exception {
if(session!=null) {
session.close();
}
}
@BeforeEach
void setUp() throws Exception {
}
@AfterEach
void tearDown() throws Exception {
}
/**
* 先增加學校再增加老師
* @throws Exception
*/
@Test
void testSave1() throws Exception {
Transaction tx = null;
try {
tx = session.beginTransaction();
School scl1 = new School(null, "黃岡中學", 233L,null);
scl1.setCreatedTime(sdf.parse("1904-12-31 00:00:00"));
scl1.setUpdatedTime(new Date());
scl1.setDescription("黃岡中學的描述");
School scl2 = new School(null, "華師一附中", 220L,null);
scl2.setCreatedTime(sdf.parse("1950-9-21 00:00:00"));
scl2.setUpdatedTime(new Date());
scl2.setDescription("華師一附中的描述");
Integer id1 = (Integer)session.save(scl1);
Integer id2 = (Integer)session.save(scl2);
Teacher t1 = new Teacher(null, "張三", "男", scl1, "張三是一名體育老師");
t1.setCreatedTime(new Date());
t1.setUpdatedTime(new Date());
t1.setDescription("張三老師的描述");
session.save(t1);
Teacher t2 = new Teacher("", "李四", "女", scl1, "李四是一名音樂老師");
t2.setCreatedTime(new Date());
t2.setUpdatedTime(new Date());
t2.setDescription("李四老師的描述");
session.save(t2);
Teacher t3 = new Teacher("", "王五", "男", scl2, "王五是一名化學老師");
t3.setCreatedTime(new Date());
t3.setUpdatedTime(new Date());
t3.setDescription("王五老師的描述");
session.save(t3);
tx.commit();
System.out.println("黃岡中學記錄主鍵:"+id1+"\r\n華師一附中記錄主鍵:"+id2);
} catch (HibernateException e) {
if (tx != null){
tx.rollback();
}
e.printStackTrace();
}
}
/**
* 先增加老師再增加學校
*/
@Test
void testSave2() {
Transaction tx = null;
try {
tx = session.beginTransaction();
School scl = new School(null, "XX高中", 1L,null);
scl.setCreatedTime(new Date());
scl.setCreatedTime(new Date());
scl.setUpdatedTime(new Date());
scl.setDescription("XX高中的描述");
// 關聯關系由Teacher維護,設定teacher類cascade = CascadeType.ALL可避免scl對象是瞬态無法儲存錯誤
// 或者session.persist(scl);
session.persist(scl);
Teacher t1 = new Teacher("", "趙六", "未知", scl, "趙六老師的備注資訊");
t1.setCreatedTime(new Date());
t1.setUpdatedTime(new Date());
t1.setDescription("趙六老師的描述");
session.save(t1);
tx.commit();
} catch (HibernateException e) {
if (tx != null){
tx.rollback();
}
e.printStackTrace();
}
}
@Test
public void deleteTeacher() {
Transaction tx = null;
try {
tx = session.beginTransaction();
String hql = "from Teacher t where t.name = ?1";
Query<?> query = session.createQuery(hql);
query.setParameter(1,"趙六");
@SuppressWarnings("unchecked")
List<Teacher> list = (List<Teacher>) query.list();
for (Teacher tec : list) {
String teacherId = tec.getTeacherId();
Integer schoolId = tec.getSchl().getSchoolId();
assertNotNull(teacherId);
session.delete(tec);
// 如果Teacher類設定為 CascadeType.ALL 檢測到學校是會被級聯删除,是以這裡設定CascadeType.MERGE
School school = session.get(School.class, schoolId);
System.out.println(school);
}
tx.commit();
} catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
}
@Test
public void findAll() {
Transaction tx = null;
try {
tx = session.beginTransaction();
List<?> employees = session.createQuery("FROM School").list();
for (Iterator<?> iterator = employees.iterator(); iterator.hasNext();) {
School sc = (School) iterator.next();
System.out.print("學校名稱: " + sc.getSchoolName());
// 因為是延遲加載,執行下面一行時才會查詢teacher資訊
// 一般一對多在一方設定fetch = FetchType.LAZY可提高效率
Set<Teacher> teachers = sc.getTeachers();
if(teachers == null) {
System.out.println(sc);
}
System.out.println("學校老師總數:"+teachers.size());
}
tx.commit();
} catch (HibernateException e) {
if (tx != null){
tx.rollback();
}
e.printStackTrace();
}
}
@Test
public void queryByHQL() {
Transaction tx = null;
try {
tx = session.beginTransaction();
String hql = "from School s order by s.ranking desc";
Query<School> query = session.createQuery(hql, School.class);
//指定從那個對象開始查詢,參數的索引位置是從0開始的,
query.setFirstResult(0);
//分頁時,一次最多産尋的對象數
query.setMaxResults(1);
List<School> list = query.getResultList();
for (School s : list) {
System.out.println(s.getSchoolName());
}
tx.commit();
} catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
}
@Test
public void queryByQBC() {
Transaction tx = null;
try {
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<School> criteria = builder.createQuery(School.class);
Root<School> from = criteria.from(School.class);
Order order = builder.desc(from.get("ranking"));
criteria.orderBy(order);
Query<School> query = session.createQuery(criteria);
//指定從那個對象開始查詢,參數的索引位置是從0開始的,
query.setFirstResult(0);
//分頁時,一次最多産尋的對象數
query.setMaxResults(1);
List<School> list = query.getResultList();
for (School s : list) {
System.out.println(s.getSchoolName());
}
tx.commit();
} catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
}
@Test
public void deleteSchool() {
Transaction tx = null;
try {
tx = session.beginTransaction();
School school = session.get(School.class, 5);
if(school!=null) {
session.delete(school);
}
tx.commit();
} catch (HibernateException e) {
if (tx != null)
tx.rollback();
e.printStackTrace();
}
}
}
總結
因為用的hibernate版本較新,而且過程中也嘗試了一些不同的設定,總之各種折騰。網上相關資料少而且無法解決問題,最終還是一步步debug,不斷嘗試,才能完成這篇部落格。總的來說還是很有收獲,畢竟以前很多東西連一知半解都算不上,但是現在整個環境搭建測試一遍,對整個hibernate的了解還是加深了很多,第一次用markdown格式寫這種正式部落格,可能排版不盡人意🐸,如果文中有不正确的地方,希望大家不吝指教😘