1 引言
最近读了一些书1或网络上的讲解,发现关于hibernate使用方法的讲解要么结合Web MVC框架讲解,要么没把运行例子所需的jar包讲解清楚。为克服上述不足,本文拟解决如下问题:
- 一个独立简单完整的关于hibernate的例子包含哪些内容;
- 运行上述例子时,究竟至少需要哪些jar包。
一些例子所需环境如下:
名称 | 版本 |
---|---|
JDK | 1.8.0_281 |
MySQL | 8.0.13 |
hibernate | 4.3.6 |
以下例子因为简单,使用手工编译和运行,没用任何IDE或Maven工具。
2 关于hibernate的一个简单独立完整的例子
项目的文件夹结构如下:
├── classes/
│ ├── com/
│ │ ├──rob/entity/User.hbm.xml
│ └── hibernate.cfg.xml
├── lib/
├── src/
│ ├── com/
│ │ ├──完整源代码文件
在MySQL中的数据库testweb中创建表如下:
CREATE TABLE tuser (
id int(11) NOT NULL AUTO_INCREMENT,
user_name varchar(45) DEFAULT NULL,
user_pwd varchar(45) DEFAULT NULL,
real_name varchar(45) DEFAULT NULL,
sex varchar(45) DEFAULT NULL,
birthday DATE DEFAULT NULL,
create_datetime TIMESTAMP,
remark varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
User.java的代码如下:
package com.rob.entity;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
public class User implements Serializable{
private Integer id;
private String userName;
private String userPwd;
private String realName;
private String sex;
private Date birthday;
private Timestamp createdatetime;
private String remark;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPwd() {
return userPwd;
}
public void setUserPwd(String userPwd) {
this.userPwd = userPwd;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
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 Timestamp getCreatedatetime() {
return createdatetime;
}
public void setCreatedatetime(Timestamp createdatetime) {
this.createdatetime = createdatetime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public User() {
}
public User(Integer id, String userName, String userPwd, String realName, String sex, Date birthday,
Timestamp createdatetime, String remark) {
super();
this.id = id;
this.userName = userName;
this.userPwd = userPwd;
this.realName = realName;
this.sex = sex;
this.birthday = birthday;
this.createdatetime = createdatetime;
this.remark = remark;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", userPwd=" + userPwd + ", realName=" + realName
+ ", sex=" + sex + ", birthday=" + birthday + ", createdatetime=" + createdatetime + ", remark="
+ remark + "]";
}
}
编译User.java的命令为:javac -d classes src\com\rob\entity\User.java
User类的与数据库表的映射文件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>
<!--
name:实体类全路径名
table:实体类对应的数据库表名称
-->
<class name="com.rob.entity.User" table="tuser">
<!--
id:用于设置数据库表结构中主键列的生成方式
name:实体类中属性名称
type:Jave的数据类型
column:数据库表字段名称
-->
<id name="id" type="java.lang.Integer" column="id">
<!--
class:定义主键列生成的方式:hibernate管理、数据库管理、开发者管理
increment,identity,sequcene,native,assgine
-->
<generator class="increment"></generator>
</id>
<!-- 与实体类相匹配 -->
<property name="userName" type="java.lang.String" column="user_name"/>
<property name="userPwd" type="java.lang.String" column="user_pwd"/>
<property name="realName" type="java.lang.String" column="real_name"/>
<property name="sex" type="java.lang.String" column="sex"/>
<property name="birthday" type="java.util.Date" column="birthday"/>
<property name="createdatetime" insert="false" update="false" type="timestamp" column="create_datetime"/>
<property name="remark" type="java.lang.String" column="remark"/>
</class>
</hibernate-mapping>
上面映射文件中的元素property中的属性type必须给出相应的值,否则,运行后会报如下错误:
Exception in thread "main" org.hibernate.MappingException: Could not determine type for: , at table: tuser, for columns: [org.hibernate.mapping.Column(sex)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:336)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:310)
at org.hibernate.mapping.Property.isValid(Property.java:241)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:496)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1358)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at com.rob.test.Demo.users(Demo.java:21)
at com.rob.test.Demo.main(Demo.java:69)
Demo.java源文件的代码如下:
package com.rob.test;
import java.util.Date;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import com.rob.entity.User;
public class Demo {
public void users() {
//创建Hibernate核心类
Configuration cfg=new Configuration();
//读取核心配置文件
cfg.configure("hibernate.cfg.xml");
ServiceRegistry sr = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties()).build();
//创建session工厂
SessionFactory sf = cfg.buildSessionFactory(sr);
//获取session
Session session = sf.openSession();
//开启事务
Transaction ts= session.beginTransaction();
System.out.println("-------------增加-------------------");
//新增
User user=new User();
user.setUserName("海王大大3");
user.setUserPwd("6663");
user.setRealName("丑");
user.setSex("女");
user.setBirthday(new Date());
user.setRemark("你好");
//新增操作
session.save(user);
System.out.println("-------------修改-------------------");
//修改(根据id修改)
/*user.setId(3);
User user2 = session.get(User.class, user.getId());
if(null!=user2) {
user2.setUserName("二狗");
session.update(user2);
} */
System.out.println("-------------删除-------------------");
//删除
/*user.setId(1);
User user2 = session.get(User.class, user.getId());
if(null!=user2) {
session.delete(user2);
}*/
System.out.println("-------------查询-------------------");
List<User> lst = (List<User>)session.createQuery("from User").list();
for (User usr : lst) {
System.out.println(usr);
}
//提交事务
ts.commit();
//释放资源
session.close();
sf.close();
}
public static void main(String[] args) {
Demo d=new Demo();
d.users();
}
}
编译Demo.java的命令为:javac -encoding utf-8 -classpath lib\hibernate-core-4.3.6.Final.jar;lib\mysql-connector-java-8.0.13.jar;classes;. -d classes src\com\rob\test\Demo.java
对上述两个源文件编译成功后,会在classes文件夹下生成相应的类文件。接下来,就具备运行该例子的条件了。
最后给出hibernate的整体配置文件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>
<!-- 数据库相关配置 -->
<!-- connection.username|connection.password|connection.url|connection.driver_class|dialect -->
<!-- 连接数据库账户名称 -->
<property name="connection.username">root</property>
<!-- 连接数据库密码(我的数据库没有登录密码,直接不用写) -->
<property name="connection.password">123456</property>
<!-- 连接的绝对路径(使用&需要解译&) -->
<property name="connection.url">
jdbc:mysql://localhost:3306/testweb?useUnicode=true&serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useSSL=false
</property>
<!-- 驱动的绝对路径 -->
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<!-- 数据库方言配置 -->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- 配置本地事务 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 调试相关配置 -->
<!-- hibernate运行过程是否展示sql命令代码(自动生成) -->
<property name="show_sql">true</property>
<!-- 是否规范输出sql代码 -->
<property name="format_sql">true</property>
<!-- 实体映射相关配置 -->
<mapping resource="com/rob/entity/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
该例子以及完备了,只待运行了。
3 该例子所依赖的jar包
本小节给出本例子依赖的完整的jar包。这是方便学习的角度,实际开发中,将会使用Maven并配合IDE工具编译和运行。所依赖的完整的jar包如下图所示:
从上图可以看出,除了mysql-connector驱动外,其他的jar包都比较老。不过没关系,上述例子照样可以运行。感兴趣的读者,完全可以切换到新版本的jar包,没什么难度。至于我为什么用一些老版本的jar包,是因为手头上正好有这些jar包,同时因为我要对一个手头上的老项目抽丝剥茧的研究。
3.1 运行命令
java -classpath lib\antlr-2.7.7.jar;lib\javassist-3.18.1-GA.jar;lib\hibernate-jpa-2.1-api-1.0.0.Final.jar;lib\jboss-transaction-api_1.2_spec-1.0.0.Final.jar;lib\jboss-logging-3.1.3.GA.jar;lib\hibernate-commons-annotations-4.0.5.Final.jar;lib\dom4j-1.6.1.jar;lib\hibernate-core-4.3.6.Final.jar;lib\mysql-connector-java-8.0.13.jar;classes;. com/rob/test/Demo
上面导入类路径时,可以用通配符*替代,从而简写上面命令。为了学习的目的,给出了完整的路径。
3.2 运行结果
3.3 按顺序给出缺少相关jar的运行报错
缺少dom4j-1.6.1.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: org/dom4j/DocumentException
at com.rob.test.Demo.users(Demo.java:17)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: org.dom4j.DocumentException
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 2 more
缺少hibernate-commons-annotations-4.0.5.Final.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: org/hibernate/annotations/common/reflection/MetadataProvider
at com.rob.test.Demo.users(Demo.java:17)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.MetadataProvider
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 2 more
缺少jboss-logging-3.1.3.GA.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/logging/BasicLogger
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$100(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.hibernate.cfg.Configuration.<clinit>(Configuration.java:192)
at com.rob.test.Demo.users(Demo.java:17)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: org.jboss.logging.BasicLogger
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 15 more
缺少jboss-transaction-api_1.2_spec-1.0.0.Final.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/transaction/SystemException
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Unknown Source)
at org.jboss.logging.Logger$1.run(Logger.java:2252)
at java.security.AccessController.doPrivileged(Native Method)
at org.jboss.logging.Logger.getMessageLogger(Logger.java:2227)
at org.jboss.logging.Logger.getMessageLogger(Logger.java:2214)
at org.hibernate.cfg.Configuration.<clinit>(Configuration.java:192)
at com.rob.test.Demo.users(Demo.java:17)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: javax.transaction.SystemException
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 9 more
缺少hibernate-jpa-2.1-api-1.0.0.Final.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: javax/persistence/EntityListeners
at org.hibernate.cfg.annotations.reflection.JPAMetadataProvider.getDefaults(JPAMetadataProvider.java:100)
at org.hibernate.annotations.common.reflection.java.JavaReflectionManager.getDefaults(JavaReflectionManager.java:252)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1386)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1928)
at com.rob.test.Demo.users(Demo.java:21)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: javax.persistence.EntityListeners
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 7 more
缺少antlr-2.7.7.jar包时,会报错如下:
Exception in thread "main" java.lang.NoClassDefFoundError: antlr/RecognitionException
at org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory.createQueryTranslator(ASTQueryTranslatorFactory.java:57)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:124)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:88)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:167)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:301)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:236)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1800)
at com.rob.test.Demo.users(Demo.java:57)
at com.rob.test.Demo.main(Demo.java:69)
Caused by: java.lang.ClassNotFoundException: antlr.RecognitionException
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 9 more
上述讲解漏掉了一个javassist-3.18.1-GA.jar包的报错讲解,请读者补充。
4 总结
本文给出了一个独立的完整的简单的hibernate的例子,能帮助我们对hibernate框架更聚焦地学习;同时,也给出了所依赖的、完备的jar包,便于我们更深刻地理解。
李刚. Struts 2.x 权威指南. 第3版. 北京: 电子工业出版社, 2012.10: 29. ↩︎