Hibernate开发环境搭建与测试

本文详细介绍了如何在Eclipse中利用Maven创建项目,配置Hibernate,建立与MySQL 8.0.15的连接,并编写SessionFactoryManager类进行初始化。文章还涉及了最小配置的hibernate.cfg.xml文件,以及如何通过注解将实体类与数据库表映射,创建Book类及其Dao层,展示了Hibernate与JDBC操作数据库的不同之处。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、环境

开发环境:

Eclipse Java EE IDE for Web Developers.

Version: 2018-09 (4.9.0)
Build id: 20180917-1800

Java运行时环境:Java SE 18.3,构建号10.0.2

mysql server版本号:8.0.15

本例不使用Eclipse的Hibernate插件(不好用)。

参考:https://www.codejava.net/frameworks/hibernate/hibernate-hello-world-tutorial-for-beginners-with-eclipse-and-mysql

2、创建测试用数据库

CREATE DATABASE 'bookstore';

3、创建项目

在Eclipse中依次打开菜单File=>New=>Maven Project

注意勾选红框内的选项,这里不需要使用Maven提供的项目原型。

创建项目。

修改项目pom文件如下:

<project
	xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.zhangdb.hibernate</groupId>
	<artifactId>HibernateHelloExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<dependencies>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>5.4.1.Final</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.15</version>
		</dependency>
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.2.11</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-core</artifactId>
			<version>2.2.11</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-impl</artifactId>
			<version>2.2.11</version>
		</dependency>
		<dependency>
			<groupId>javax.activation</groupId>
			<artifactId>activation</artifactId>
			<version>1.1.1</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<source>10</source>
					<target>10</target>
					<encoding>UTF-8</encoding>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

说明如下:

hibernate-core:hibernate构架核心jar包,5.4.1.Final版本发布于2019年1月份,现在是最新版本。

mysql-connector-java:mysql JDBC驱动。版本号为8.0.15,与我的mysql服务器版本一致。注意要避免出现服务器版本与驱动版本不一致的情况,否则会出现各种问题。

jaxb-api、jaxb-core、jaxb-impl、activation四个包,Hibernate用来解析xml配置文件。在旧版Java SE环境中,这四个包是默认包含的,在最新版本中,好像是从Java SE 9开始,需要手动引入。

build部分:与自己的Java环境一致就行。

修改完pom文件后,执行Maven的Update Project命令,让Maven载入相关的软件包。

至此环境装备完毕。

4、配置Hibernate

在src/main/resources目录下添加名为hibernate.cfg.xml文件,修改其内容为:

<?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>
		<!-- Database connection settings -->
		<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://192.168.56.101:3306/bookstore?useSSL=false</property>
		<property name="connection.username">billy</property>
		<property name="connection.password">123456</property>
		<property name="show_sql">true</property>
	</session-factory>
</hibernate-configuration>

注意connection.driver_class的值,因为我使用的mysql版本是8.0.15,它的驱动是com.mysql.cj.jdbc.Driver,有些旧版本为com.mysql.jdbc.Driver。另外connection.url中useSSL必需设置成false,否则默认使用SSL连接。看其它人的网文,好像有什么时区的问题,需要在connection.url中特别指定,我没有遇到这个问题。

此时配置文件中只包含与mysql连接相关信息,不包括具体的表信息以及表与实体之间的映射信息,当然以上是最小配置,全部可用的配置需要查看Hibernate的官方文档,特别一点的属性show_sql设置成true,作用是将执行的SQL语句打印到控制台,方便看Hibernate到底做了什么事情。

从session-factory的内容看,类似与JDBC的connection配置。Hibernate从这里读取配置文件并创建与mysql服务器的连接池,在这里写一个类,专门用来完成此工作。

在项目中创建package:

选中Package com.zhangdb.hibernate点右键创建类 SessionFactoryManager,修改后如下:

package com.zhangdb.hibernate;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

public class SessionFactoryManager {

	private SessionFactory sessionFactory = null;

	public void initSessionFactory() {
		final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
		try {
			sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
		} catch (Exception ex) {
			System.out.println(ex);
			StandardServiceRegistryBuilder.destroy(registry);
		}
	}

	public void exitSessionFactory() {
		if ((sessionFactory != null) && (!sessionFactory.isClosed())) {
			sessionFactory.close();
		}
		sessionFactory = null;
	}

	public Session openSession() {
		if ((sessionFactory != null) && (!sessionFactory.isClosed())) {
			return sessionFactory.openSession();
		} else {
			// throw exception
			return null;
		}
	}

	public static void main(String[] args) {
		SessionFactoryManager sessionFactoryManager = new SessionFactoryManager();
		// 初始化session factory
		sessionFactoryManager.initSessionFactory();
		// 打开session
		Session session = sessionFactoryManager.openSession();
		// 执行show tables命令
		@SuppressWarnings("unchecked")
		List<String> tables = session.createSQLQuery("show tables").list();
		for (String item : tables) {
			System.out.println(item);
		}
		// 关闭session
		session.close();
		// 关闭session factory
		sessionFactoryManager.exitSessionFactory();
	}
}

方法initSessionFactory用来初始化Hibernate数据源,从class path查找配置文件然后初始化,与以前的JDBC初始化差不多。 Hibernate的版本一直在演进,现在大版本号来到了5。不同版本的Hibernate它的session factory初始化方法可能不一样,另外还有其它第三方也提供的初始化的方法,所以这里的初始化代码可能与一些网文、教材上不一样,无需奇怪。有一点要引起重视,你用的是那个版本的Hibernate,你就去官网上查看相应版本的初始化方法,不要用版本不匹配的初始化方法,也不要用第三方提供的初始方法,否则会出问题。关于session factory的初始化,Hibernate官网专门有一个topic,参考这里:http://docs.jboss.org/hibernate/orm/5.4/topical/html_single/bootstrap/NativeBootstrapping.html。另外http://docs.jboss.org/hibernate/orm/5.4/quickstart/html_single/里一个最简单的实现,我这段代码就是从这个地方抄的。

刚才说了,这个配置文件是最小化配置,可以看到,里边并没有连接池的相关配置,比如最小连接、最大连接、连接不够用了怎么办等。这种情况下,Hibernate会使用内置的连接池管理器,但是要注意,这个内置连接池管理器非常简单,而且还有bugger,它存在的目的是开发环境下的测试。关于Hibernate连接池的管理问题也是一个单独的topic,我打算另外写一篇文章来研究这个问题。

方法exitSessionFactory的作用是关闭数据源连接。

方法openSession的作用是打开一个session,session代表与数据源的一个交互过程,既然它是session,就是一个会话,那么它就是有状态的,有开始也要有结束,所以用完了session要及时关掉。

然后就是main方法,这个主要用来测试,注释中有解释。注意其中的List<String> tables = session.createSQLQuery("show tables").list();这句话。createSQLQuery方法的作用是创建标准的SQL查询语句,session还有一个方法叫作createQuery,这个方法的作用是创建Hibernate特有的查询语句,就是所谓的HQL,它的语法与标准SQL不一样,当然Hibernate最后根据所使用的JDBC驱动类型以及配置文件中指定的方言(此例中没有指定,使用默认)、以及实体类中的注解,翻译成标准的SQL,最后执行。

总之,目前看来,Hibernate即能执行标准SQL也能执行HQL,使用那种用session中的方法作区别。

另一个与JDBC不同的地方就是List<String> tables = session.createSQLQuery("show tables").list();的返回值类型。在JDBC中,返回类型是ResultSet,需要我们编写代码解析,而在Hibernate中,返回的是List类型。

在控制台中确认一下结果,此时数据库中没有创建表,所以没有返回表名称,但是证明通过Hibernate已经能连接到数据库并能执行SQL语句。

5、创建表以及相应实体类

首先在数据库bookstore中创建book表:

USE 'bookstore';
 
CREATE TABLE `book` (
  `book_id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(128) NOT NULL,
  `author` varchar(45) NOT NULL,
  `price` float NOT NULL,
  PRIMARY KEY (`book_id`),
  UNIQUE KEY `book_id_UNIQUE` (`book_id`),
  UNIQUE KEY `title_UNIQUE` (`title`)
) ENGINE=InnoDB;

选中Package com.zhangdb.hibernate点右键创建类Book,修改后如下:

package com.zhangdb.hibernate;

public class Book {
	private long id;
	private String title;
	private String author;
	private float price;

	public Book() {
	}

	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public float getPrice() {
		return price;
	}

	public void setPrice(float price) {
		this.price = price;
	}

	@Override
	public String toString() {
		return "Book [id=" + id + ", title=" + title + ", author=" + author + ", price=" + price + "]";
	}
}

Hibernate通过注解(也可以通过配置文件)将实体类与数据库中的表映射起来。这里用到的注解本身是Java的一种规范,java有自己的实现,Hibernate也有它自己的实现,而且Hibernate的注解不仅实现了java规范,还有额外的功能。在一些比较老的教材中,会告诉你为了使用Hibernate实现的注解,需要将hibernate-annotations、hibernate-entitymanager等包引入项目。在新版本的Hibernate中,这些都不用了。首先hibernate-annotations这个包从2010年起就不更新了,可能是官方觉得这东西没什么用处,直接使用java自带的标准注解就可以。另外hibernate-entitymanager这个包也不要了,它被合并到hibernate-core包中了。

接下来引入包含注解的包import javax.persistence。
然后再添加注解,修改后内容如下:

import javax.persistence.*;

@Entity
@Table(name = "book")
public class Book {
	private long id;
	private String title;
	private String author;
	private float price;

	public Book() {
	}

	@Id
	@Column(name = "book_id")
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	@Column(name = "title")
	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	@Column(name = "author")
	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	@Column(name = "price")
	public float getPrice() {
		return price;
	}

	public void setPrice(float price) {
		this.price = price;
	}
}

关于注解可查看官方文档,总结一下就是这个实例类通过注解的形式,说明它与表book映射,并且成员的getter方法的注解说明了类成员与表中列的对应关系。Hibernate正是根据这里定义的映射关系,以及我们提供的简单的SQL\HQL语句,来翻译成复杂的SQL语句,并用查询到的结果填充我们自己定义的实体类。当然,这里只是简单的示例,实际应用中实体类与表的映射关系很复杂,这个以后再研究。

除了映射关系,这个实体类与JDBC中的实体类就没有其它区别了,它只是一个数据的载体,不涉及到具体操作。

接下来修改hibernate.cfg.xml配置文件,让它知道Book是类是用来进行映射的,只需要加入一句话:<mapping class="com.zhangdb.hibernate.Book" />,修改以后内容如下:

<?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>
		<!-- Database connection settings -->
		<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://192.168.56.101:3306/bookstore?useSSL=false</property>
		<property name="connection.username">billy</property>
		<property name="connection.password">******</property>
		<property name="show_sql">true</property>

		<mapping class="com.zhangdb.hibernate.Book" />
	</session-factory>
</hibernate-configuration>

6、为Book类创建Dao层

Book类的Dao层可以定得很复杂,这里的话只是创建简单实现CRUD的Dao层,主要看下Hibernate与JDBC在实现上有什么不同。

选中Package com.zhangdb.hibernate点右键创建类BookCRUDDao类,修改后如下:

package com.zhangdb.hibernate;

import org.hibernate.Session;

public class BookCRUDDao {

	private SessionFactoryManager sessionFactoryManager = null;

	public SessionFactoryManager getSessionFactoryManager() {
		return sessionFactoryManager;
	}

	public void setSessionFactoryManager(SessionFactoryManager sessionFactoryManager) {
		this.sessionFactoryManager = sessionFactoryManager;
	}

	public void clearSessionFactoryManager() {
		sessionFactoryManager = null;
	}

	public void create(Book book) {
		Session session = sessionFactoryManager.openSession();
		session.beginTransaction();
		// 持久化临时对象
		session.save(book);
		session.getTransaction().commit();
		session.close();
	}

	public Book read(long bookId) {
		Session session = sessionFactoryManager.openSession();
		Book book = session.get(Book.class, bookId);
		session.close();
		return book;
	}

	public void update(Book book) {
		Session session = sessionFactoryManager.openSession();
		session.beginTransaction();
		session.update(book);
		session.getTransaction().commit();
		session.close();
	}

	protected void delete(long bookId) {
		Book book = new Book();
		book.setId(bookId);

		Session session = sessionFactoryManager.openSession();
		session.beginTransaction();
		session.delete(book);
		session.getTransaction().commit();
		session.close();
	}

	public static class TestBookCRUDDaoCreate {
		public static void main(String[] args) {
			SessionFactoryManager sessionFactoryManager = new SessionFactoryManager();
			// 初始化session factory
			sessionFactoryManager.initSessionFactory();

			// 创建Book的Dao层
			BookCRUDDao bookCRUDDao = new BookCRUDDao();
			// 设置sessionFactoryManager
			bookCRUDDao.setSessionFactoryManager(sessionFactoryManager);

			Book book = new Book();

			for (int i = 0; i < 10; i++) {
				book.setTitle("Effective Java" + i);
				book.setAuthor("Joshua Bloch");
				book.setPrice(32.59f);

				bookCRUDDao.create(book);
			}

			// 解除对sessionFactoryManager的引用
			bookCRUDDao.clearSessionFactoryManager();
			// 关闭session factory
			sessionFactoryManager.exitSessionFactory();
		}
	}

	public static class TestBookCRUDDaoRead {
		public static void main(String[] args) {
			SessionFactoryManager sessionFactoryManager = new SessionFactoryManager();
			// 初始化session factory
			sessionFactoryManager.initSessionFactory();

			// 创建Book的Dao层
			BookCRUDDao bookCRUDDao = new BookCRUDDao();
			// 设置sessionFactoryManager
			bookCRUDDao.setSessionFactoryManager(sessionFactoryManager);

			for (int i = 0; i < 10; i++) {
				System.out.println(bookCRUDDao.read(i + 1));
			}

			// 解除对sessionFactoryManager的引用
			bookCRUDDao.clearSessionFactoryManager();
			// 关闭session factory
			sessionFactoryManager.exitSessionFactory();
		}
	}

	public static class TestBookCRUDUpdate {
		public static void main(String[] args) {
			SessionFactoryManager sessionFactoryManager = new SessionFactoryManager();
			// 初始化session factory
			sessionFactoryManager.initSessionFactory();

			// 创建Book的Dao层
			BookCRUDDao bookCRUDDao = new BookCRUDDao();
			// 设置sessionFactoryManager
			bookCRUDDao.setSessionFactoryManager(sessionFactoryManager);

			Book book = new Book();

			for (int i = 0; i < 10; i++) {
				book.setId(i + 1);
				book.setTitle("Effective C++" + i);
				book.setAuthor("Joshua Bloch");
				book.setPrice(22.59f);
				bookCRUDDao.update(book);
				;
			}

			// 解除对sessionFactoryManager的引用
			bookCRUDDao.clearSessionFactoryManager();
			// 关闭session factory
			sessionFactoryManager.exitSessionFactory();
		}

		public static class TestBookCRUDDelete {
			public static void main(String[] args) {
				SessionFactoryManager sessionFactoryManager = new SessionFactoryManager();
				// 初始化session factory
				sessionFactoryManager.initSessionFactory();

				// 创建Book的Dao层
				BookCRUDDao bookCRUDDao = new BookCRUDDao();
				// 设置sessionFactoryManager
				bookCRUDDao.setSessionFactoryManager(sessionFactoryManager);

				for (int i = 0; i < 10; i++) {
					bookCRUDDao.delete(i + 1);
				}

				// 解除对sessionFactoryManager的引用
				bookCRUDDao.clearSessionFactoryManager();
				// 关闭session factory
				sessionFactoryManager.exitSessionFactory();
			}
		}

	}
}

在上边的类中,提供了create、read、update、delete四个方法,分别对应Book类的CRUD操作,并提供了四个静态内部类,充当测试床,可分别运行它们,然后通过命令行查看一下数据库,确认结果是否是正确的。

在控制台中,可以看到Hibernate到底做了什么事情,本质上Hibernate的低层还是JDBC。

通过以上的测试可以确定一些事情,实体类及其注解非常重要,Hibernate根据其中确定的映射关系(实体类与表、实体类成员与表中的列等),能够自动生成SQL语句,最重要的是它能自动填充实体类,而非像JDBC中需要我们自己解析返回的结果,大大简化了代码量。

另外Hibernate相当于充当了虚拟数据库的功能,隐藏低层数据库的实现细节。如果把Mysql数据库换成其它产品,则只需要修改一下配置就可实现,不用改代码。

以上示例很简单,没有涉及复杂查询,只需要调用正确的方法,不用写任何一句SQL,返回的结果也由Hibernate自动解析,非常方便。

对于复杂查询,如多表查询、级联查询等,仍然需要写查询语句,不过是HQL而非SQL,同时要定义复杂的实体类并通过注解指明各种复杂的映射关系。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值