通过Hibernate5.3.X连接MySQL8.0.X的基本设定与案例

主要参考资料

关于MySQL8.0.11连接JDBC代码及连接Hibernate-5.3.1.Final时Hibernate.cfg.xml文件的写法遇到的问题及解决过程

0、版本信息

(1)OS:Window7 sp1 x64

(2)JDK:jdk-10.0.0.2

(3)Hibernate:5.3.4 Final

(4)MySQL:8.0.11

1、主要过程

(1)通过JDBC连接MySQL。主要用于验证连接、访问MySQL数据库的各个设置的正确性,在通过Hibernate连接MySQL时则可以排除连接参数设定错误。

(2)实现通过Hibernate访问MySQL。测试验证连接MySQL时如何通过文件配置Hibernate,为Hibernate集成到其他框架(如SSH)里提供参考设定。

2、JDBC连接MySQL

(1)创建项目。新建Maven项目hibernate_test, archetype 选择【Maven- archetype -quickstart】。

(2)配置日志。在项目【src/main/resources】中添加日志显示配置文件log4j.properties,设置信息显示级别为DEBUG,便于分析程序的工作过程。代码内容如下。

log4j.rootLogger=DEBUG,ACT

log4j.appender.ACT=org.apache.log4j.ConsoleAppender
log4j.appender.ACT.layout=org.apache.log4j.PatternLayout
log4j.appender.ACT.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n

(3)配置pom.xml文件,导入必要的包文件。文件内容如下。

<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.seu.liuds</groupId>
	<artifactId>hibernate_test</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>hibernate_test</name>
	<url>http://maven.apache.org</url>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<java.version>10.0.0.2</java.version>
	</properties>

	<dependencies>
		<!-- 单元测试框架 -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.10</version>
			<scope>test</scope>
		</dependency>
		
		<!-- MySQL的JDBC驱动包 -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.11</version>
		</dependency>

		<!-- 数据库连接池 -->
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-c3p0</artifactId>
			<version>5.3.4.Final</version>
		</dependency>
		<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>mchange-commons-java</artifactId>
			<version>0.2.15</version>
		</dependency>

		<!-- hibernate核心包 -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>5.3.4.Final</version>
		</dependency>

		<!-- Java对象与XML文档的互相转换 -->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-impl</artifactId>
			<version>2.3.0</version>
		</dependency>
		<dependency>
			<groupId>com.sun.xml.bind</groupId>
			<artifactId>jaxb-core</artifactId>
			<version>2.3.0</version>
		</dependency>
		
		<!-- 日志记录 -->
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
	</dependencies>
</project>

(4)在MySQL中新建/选择数据库作为连接对象,此处选择【sshdemo】,并在数据库sshdemo中建立一个表格user。本例子采用MySQL Workbench工具完成数据库和表格的创建。

(5)创建包含main()方法的类JDBCTest,包名选择【com.seu.liuds.hibernate_test.controller】,用于实现与MySQL的连接测试。代码如下。

package com.seu.liuds.hibernate_test.controller;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class JDBCTest {

	// JDBC驱动名,MySQL6以后的JDBC驱动
	static final String JDBC_DRIVER = "com.mysql.cj.jdbc.Driver";
	// 数据库 URL,必須手动禁用SSL且设定时区,此处设定为东8区
	static final String DB_URL = "jdbc:mysql://localhost:3306/sshdemo?useSSL=false&serverTimezone=GMT%2B8";

	// 数据库的用户名与密码,需要根据自己的设置
	static final String USER = "root";
	static final String PASS = "";

	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			System.out.println("Connect to database...");
			// 注册JDBC驱动,
			Class.forName(JDBC_DRIVER);
			System.out.println("URL = " + DB_URL + "\nUSR = " + USER + "\nPWD = " + PASS);
			// 创建连接
			conn = DriverManager.getConnection(DB_URL, USER, PASS);
			// 关闭自动提交,开启事务
			conn.setAutoCommit(false);
			// 定义SQL语句,刪除id = 1的数据项
			String sql = "delete from user where id = ?";
			ps = conn.prepareStatement(sql);
			ps.setInt(1, 1);
			// 执行SQL语句
			int count = ps.executeUpdate();
			System.out.println(count);
			// 提交事务
			conn.commit();
		} catch (Exception e) {
			// 回滚事务
			try {
				conn.rollback();
			} catch (SQLException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} finally {
			// 关闭资源
			if (ps != null) {
				try {
					ps.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}

执行JDBCTest.java,运行结果如下:

Connect to database...
URL = jdbc:mysql://localhost:3306/sshdemo?useSSL=false&serverTimezone=GMT%2B8
USR = root
PWD = 
0

上述结果说明,MySQL数据库工作正常,通过JDBC连接MySQL的参数设置正确,即

jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.db.url = jdbc:mysql://localhost:3306/sshdemo?useSSL=false&serverTimezone=GMT%2B8
jdbc.user = root
jdbc.password = 

3、Hibernate连接MySQL

Hibernate是一个开源的对象/关系映射(ORM)框架,它对JDBC进行了轻量级的封装,借助它可以使用面向对象的方法来操作和使用数据库。通过Hibernate连接MySQL具体包括以下四个步骤:

(1)配置Hibernate;

(2)创建持久化类;

(3)创建持久化类的映射配置文件;

(4)通过Hibernate API操作数据库。

下面分别阐述。

3.1 配置Hibernate

关于Hibernate的配置问题,《Hibernate的配置详解》阐释的比较清楚,主要完成以下三项工作:

(1)加载数据库相关信息

(2)Hibernate的相关配置

(3)加载映射配置文件

这里(1)(2)项采用hibernate.properties文件设定,存放在src/main/resources目录中,代码如下。

# MySQL JDBC information
hibernate.connection.driver_class = com.mysql.cj.jdbc.Driver
hibernate.connection.url = jdbc:mysql://localhost:3306/sshdemo?useSSL=false&serverTimezone=GMT%2B8
hibernate.connection.username = root
hibernate.connection.password = 

# Hibernate configuration
hibernate.dialect = org.hibernate.dialect.MySQL8Dialect
hibernate.hbm2ddl.auto = update
hibernate.show_sql = false
hibernate.format_sql = true
connection.pool_size = 20
hibernate.current_session_context_class = thread

# Hibernate for c3p0
hibernate.connection.provider_class = org.hibernate.c3p0.internal.C3P0ConnectionProvider
hibernate.c3p0.max_size = 20
hibernate.c3p0.min_size = 5
hibernate.c3p0.timeout = 120
automaticTestTable = Test
hibernate.c3p0.max_statements = 100
hibernate.c3p0.acquire_increment = 1
c3p0.testConnectionOnCheckout = true
c3p0.idleConnectionTestPeriod = 18000
c3p0.idle_test_period = 120

如果希望在控制台查看Hibernate输出的MySQL语句,可设置【hibernate.show_sql = true】。针对C3P0的设置可以删除,在一般开发环境下看不出有太多影响。 

(3)加载映射配置文件项采用hibernate.cfg.xml文件设定。

因为在Eclipse中开发,所以hibernate.cfg.xml存放在src/main/resources/目录下,内容入下。

<?xml version="1.0" encoding="UTF-8"?>
<!-- ~ Hibernate, Relational Persistence for Idiomatic Java ~ ~ License: 
    GNU Lesser General Public License (LGPL), version 2.1 or later. ~ See the 
    lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. -->
<!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>
        <!-- 列出所有映射配置文件 -->
        <mapping resource="com/seu/liuds/hibernate_test/entity/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

其中,映射配置文件的名称是:类名.hbm.xml,一般放置在实体类所在的包下,用于建立表与类之间的映射关系。此处,将建立一个名为User的持久化类,并建立映射配置文件User.hbm.xml,二者均存放在src/main/com/seu/liuds/hibernate_test/entity/目录下。

3.2 创建持久化类

创建持久化类com.seu.liuds.hibernate_test.entity.User,里面包含一些基本的用户信息。

package com.seu.liuds.hibernate_test.entity;

import java.util.Date;

public class User {

	private int id;
	private String name;
	private int age;
	private String sex;
	private Date birthday;
	private String address;

	public User() {
	}

	// 使用指定ID方式确定主键的时候,采用该方法
	public User(int id, String name, int age, String sex, Date birthday, String address) {
		this.id = id;
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.birthday = birthday;
		this.address = address;
	}

	// 使用非指定ID方式确定主键的时候,采用该方法
	public User(String name, int age, String sex, Date birthday, String address) {
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.birthday = birthday;
		this.address = address;
	}

	public int getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + ", age=" + age + ", sex=" + sex + ", birthday=" + birthday
				+ ", address=" + address + "]";
	}
}

后续可以考虑采用@Data注解创建类中的主要方法,此处略过。

3.3 创建映射配置文件

映射配置文件的主要作用就是将持久化类与数据库表进行映射。这里将User类映射为一个名为user的表,将对象的属性映射为数据库的列,将属性的类型映射为数据库列的类型。

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-9-19 19:59:35 by Hibernate Tools 3.4.0.CR1 -->
<!-- 注意包名。不写的话下面的class name要写全限定名 -->
<hibernate-mapping package  = "com.seu.liuds.hibernate_test.entity">
	<!-- name:即实体类的全名;table:映射到数据库里面的表的名称 -->
	<class name="User" table="user">
	<!-- class下必须要有一个id的子元素,用于描述主键 -->
		<id name="id" type="int">
			<column name="ID" />
			<!-- 主键生成策略:由底层数据库生成标识符 -->
			<generator class="increment" />
		</id>
		<!-- 使用property来描述属性与字段的对应关系 -->
		<property name="name" type="java.lang.String">
			<column name="NAME"/>
		</property>
		<property name="age" type="int">
			<column name="AGE" />
		</property>
		<property name="sex" type="java.lang.String">
			<column name="SEX" />
		</property>
		<property name="birthday" type="java.util.Date">
			<column name="BIRTHDAY" />
		</property>
		<property name="address" type="java.lang.String">
			<column name="ADDRESS" />
		</property>
	</class>
</hibernate-mapping>

3.4 通过Hibernate API操作MySQL数据库

在项目中的src/test/java中创建测试程序com.seu.liuds.hibernate_test.UserTest。具体操作包括:

(1)连接MySQL数据库;

(2)删除一条记录;

(3)关闭连接。

package com.seu.liuds.hibernate_test;
 
import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.seu.liuds.hibernate_test.entity.User;
 
public class UserTest {
	
	private SessionFactory sessionFactory;
	private Session session;
	private Transaction transaction;
 
	@Before
	public void init() {
		System.out.println("Initialization");
		//创建配置对象
		Configuration config = new Configuration().configure();	
		//创建会话工厂对象
		sessionFactory = config.buildSessionFactory();
		//创建会话对象
		session = sessionFactory.openSession();
		//开启事务
		transaction = session.beginTransaction();
	}
	
	@After
	public void destory() {
		System.out.println("Test End.");
		//提交事务
		transaction.commit();
		//关闭会话
		session.close();
		//关闭会话工厂
		sessionFactory.close();		
	}
		
	@Test
	public void saveNewUser() throws Exception{
		System.out.println("Testing...");
		User usr = new User("赵六", 30, "男", new Date(), "北京市");
		session.save(usr);
		System.out.println("Current ID is: "+ usr.getId());
	}	
}

将日志显示级别设定为ERROR时,运行结果如下:

Initialization
Testing...
Current ID is: 5
Test End.

Current ID为当前user表中最大id序号,每执行一次,新增一条记录,该值自动加1。显然,通过Hibernate连接并操作MySQL数据库成功。

4、遗留问题

将日志显示级别设定为DEBUG时,会出现如下调试信息,虽然不影响程序运行和功能实现,总觉得心里梗梗的,查了大量的中外网站,也没有找到清除这些信息的方法,希望有高手指点一二,拜谢!

4.1 良性警告信息

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.sun.xml.bind.v2.runtime.reflect.opt.Injector (file:/D:/maven_repo/com/sun/xml/bind/jaxb-impl/2.3.0/jaxb-impl-2.3.0.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int)
WARNING: Please consider reporting this to the maintainers of com.sun.xml.bind.v2.runtime.reflect.opt.Injector
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

Oracle官方博客在《WebLogic Server and Java SE 9》一文中给出如下解释:

The illegal reflective access warnings are coming from code that has been updated to work on JDK9 but the logic checks if the JDK8 approach works first.  The warnings will go away when the default is (or you run explicitly with)  --illegal-access=deny.

言下之意应该是代码运行在JDK9上,而逻辑检查首先查找JDK8的路径。可以参考《非法反射 An illegal reflective access operation has occurred》一文。目前只能置之不理。

4.2 C3P0连接池的调试信息

03:14:30,882 [main] DEBUG com.mchange.v2.c3p0.impl.NewPooledConnection  - com.mchange.v2.c3p0.impl.NewPooledConnection@78a0ff63 closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
	at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:566)
……

 网上一篇比较深入分析的文章《java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE 的理解》显示,经过分析源码,得到的结论是这个异常可以无视掉。而在《DEBUG STACK TRACE for PoolBackedDataSource.close().》中,则认为这是可以通过Spring设定来解决的。为此,专门研读了《Hibernate配置C3P0连接池》了一文,待研究SSH时验证此法是否可行。

4.3 Hibernate dialect解析错误提示

03:14:31,139 [main] DEBUG org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl  - Unable to resolve connection default schema
org.hibernate.HibernateException: Use of DefaultSchemaNameResolver requires Dialect to provide the proper SQL statement/command but provided Dialect [org.hibernate.dialect.MySQL8Dialect] did not return anything from Dialect#getCurrentSchemaCommand
	at org.hibernate.engine.jdbc.env.internal.DefaultSchemaNameResolver$SchemaNameResolverFallbackDelegate.resolveSchemaName(DefaultSchemaNameResolver.java:100)
……

信息显示:无法解析默认的连接模式。原因是设置的MySQL8Dialect没有给DefaultSchemaNameResolver提供必需的SQL声明或者命令。但是,程序的执行并没有收到影响,连接和访问数据库都正常,这个问题怎么破?

致谢

本文成文过程中,参考了诸多高手的文章,除了在正文中引用的文章以外,还包括以下文章,在此一并感谢。

(1)CSDN博主李阿昀的关于Hibernate框架的系列文章

(2)博园网博主酒皇关于Hibernate的系列文章

(3)《记更新MySQL 8.0后踩过的那些坑

(4)《总结SSH阶段常见的异常系列之一hibernate

(5)《Hibernate学习笔记(一)——简单的Hibernate实例入门

(6)《关于Hibernate 5 和 Hibernate 4 在创建SessionFactory的不同点分析(解决 org.hibernate.MappingException: Unknown entity: xx类报错问题)

(7)《Javaweb或javaEE完整项目名及包名、资源名命名规则

(8)《如何去除get,set方法。@Data注解和如何使用,lombok

(9)《Reducing Boilerplate Code with Project Lombok

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值