精通hibernate-Hibernate 5.X的使用概述与示例

Hibernate的更新有时让人觉得反复无常,当我们在Hibernate3习惯使用conf.buildSessionFactory();时,在Hibernate4中又推荐使用ServiceRegistry来创建:configuration.buildSessionFactory(serviceRegistry)原有的buildSessionFactory()方法被Deprecated;到了Hibernate5似乎又改了,真是随性,坑了主动更新的小白们。这次复习博客系列就顺带着从入门到高级,按照Hibernate5的新特性整理一遍。一张图回顾Hibernate使用的四大步骤:Step 1.创建一个hibernate配置文件包含hibernate运行的最基本的信息。比如,连接数据库的user和password,java class,url,数据库使用的方言Dialect。

Step 2.创建持久化类Step 3.创建 对象-关系 映射文件这个是ORM框架的核心基础,定义了应用实体类对应于数据库的哪一张表,属性与哪一个字段对应。
Step 4.通过Hibernate API 编写访问数据库的代码下面我们逐步来看:Step 1.创建一个hibernate配置文件new一个文件,安装了jbosstools-4.4.2.Final-updatesite-core.zip之后(方法参考本系列上一篇博客),我们就可以方便的使用自带的Hibernate配置文件了,里面会自动为我们生成我们需要的xml标签。按照向导做即可。 这里我们配置数据库连接的几个基本信息,一会儿会插件为帮我们自动插入到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> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/happybksdb</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password"></property> <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property> </session-factory> </hibernate-configuration> 看,在向导的帮助下,配置项被自动生成了。并且各个配置项都带有前缀,这些在单单使用hibernate时并不是必须的,但是在hibernate与spring集成时确实必须的。 比如mysql和oracle的方言在处理分页时就不一样,mysql是limit,oracle是row_number。数据库种类的不同、版本的不同、引擎的不同,都需要我们通过方言的定义来告诉hibernate。你可以通过查找hibernate源码中的一个配置文件(project/etc/hibernate.properties)里面罗列了可供配置的各个数据库的数据库方言的生命形式。这里罗列出来,方便日后查找复制。DB2 org.hibernate.dialect.DB2Dialect  DB2 AS/400 org.hibernate.dialect.DB2400Dialect  DB2 OS390 org.hibernate.dialect.DB2390Dialect  PostgreSQL org.hibernate.dialect.PostgreSQLDialect  MySQL org.hibernate.dialect.MySQLDialect  MySQL with InnoDB org.hibernate.dialect.MySQLInnoDBDialect  MySQL with MyISAM org.hibernate.dialect.MySQLMyISAMDialect  Oracle (any version) org.hibernate.dialect.OracleDialect  Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect  Sybase org.hibernate.dialect.SybaseDialect  Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect  Microsoft SQL Server org.hibernate.dialect.SQLServerDialect  SAP DB org.hibernate.dialect.SAPDBDialect  Informix org.hibernate.dialect.InformixDialect  HypersonicSQL org.hibernate.dialect.HSQLDialect  Ingres org.hibernate.dialect.IngresDialect  Progress org.hibernate.dialect.ProgressDialect  Mckoi SQL org.hibernate.dialect.MckoiDialect  Interbase org.hibernate.dialect.InterbaseDialect  Pointbase org.hibernate.dialect.PointbaseDialect  FrontBase org.hibernate.dialect.FrontbaseDialect  Firebird org.hibernate.dialect.FirebirdDialect 然后我们在刚才自动生成的hibernate.cfg.xml基础上再追加一些基本配置,十分有用。这里需要注意,url被声明为jdbc:mysql://localhost:3306/happybksdb?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false这后面加入的参数是必须要的:characterEncoding=utf8设置了编码,这个无需多言。serverTimezone等也是不可少的,否则你在创建SessionFactory时会报错:Caused by: java.sql.SQLException: The server time zone value '?й???????' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support. 还要需要注意的是url中参数之间应该是&符号分割,但是卸载xml中时,由于&有特殊意义。所以需要转义,需要写成&,否则会报错:Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[9,126] Message: 对实体 "characterEncoding" 的引用必须以 ';' 分隔符结尾。 Step 2.创建持久化类package com.happybks.hibernate.hibernatePro.beans; import java.sql.Date; import java.sql.Timestamp; public class CuntomerBean { private String name; private Integer no; private Integer cid; private Long score; private double money; private Date registerDate; private Timestamp loginTime; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getNo() { return no; } public void setNo(Integer no) { this.no = no; } public Integer getCid() { return cid; } public void setCid(Integer cid) { this.cid = cid; } public Long getScore() { return score; } public void setScore(Long score) { this.score = score; } public double getMoney() { return money; } public void setMoney(double money) { this.money = money; } public Date getRegisterDate() { return registerDate; } public void setRegisterDate(Date registerDate) { this.registerDate = registerDate; } public Timestamp getLoginTime() { return loginTime; } public void setLoginTime(Timestamp loginTime) { this.loginTime = loginTime; } public CuntomerBean() { super(); // TODO Auto-generated constructor stub } @Override public String toString() { return "CuntomerBean [name=" + name + ", no=" + no + ", cid=" + cid + ", score=" + score + ", money=" + money + ", registerDate=" + registerDate + ", loginTime=" + loginTime + "]"; } } 这里,我将例子中的各个字段涵盖了常用的各个数据类型。并且,我有意将id字段命名成cid,成员变量和属性get、set方法的顺序我也将其放到了第三位,cid也不是第一个Integer的属性(位置第一个Integer类型的属性是no),看看等会自动生成映射文件时会发生什么。 Step 3.创建 对象-关系 映射文件这个应该是ORM框架的核心,建立应用实体类与数据库关系表之间的映射。现在操作如下:  看,自己跑出来了。<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2017-1-8 11:45:40 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="com.happybks.hibernate.hibernatePro.beans.CuntomerBean" table="CUNTOMERBEAN"> <id name="cid" type="java.lang.Integer"> <column name="CID" /> <generator class="assigned" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="no" type="java.lang.Integer"> <column name="NO" /> </property> <property name="score" type="java.lang.Long"> <column name="SCORE" /> </property> <property name="money" type="double"> <column name="MONEY" /> </property> <property name="registerDate" type="java.sql.Date"> <column name="REGISTERDATE" /> </property> <property name="loginTime" type="java.sql.Timestamp"> <column name="LOGINTIME" /> </property> </class> </hibernate-mapping> 值得注意的是,JBOSS的这个给eclipse的hibernate插件很智能地把cid设置成了主键。看来无论你的实体类定义中主键对应的getset属性方法、成员变量的位置是否是第一个,或者说Integer类型的第一个,只要属性的名字中带有id,都会被默认设置成为映射文件的主键id。这里我们希望主键能够自己生成,所以做了修改。<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <!-- Generated 2017-1-8 11:45:40 by Hibernate Tools 3.5.0.Final --> <hibernate-mapping> <class name="com.happybks.hibernate.hibernatePro.beans.CuntomerBean" table="CUNTOMERBEAN"> <id name="cid" type="java.lang.Integer"> <column name="CID" /> <!-- 指定主键的生成方式 :native使用数据库本地的生成方式--> <generator class="native" /> </id> <property name="name" type="java.lang.String"> <column name="NAME" /> </property> <property name="no" type="java.lang.Integer"> <column name="NO" /> </property> <property name="score" type="java.lang.Long"> <column name="SCORE" /> </property> <property name="money" type="double"> <column name="MONEY" /> </property> <property name="registerDate" type="java.sql.Date"> <column name="REGISTERDATE" /> </property> <property name="loginTime" type="java.sql.Timestamp"> <column name="LOGINTIME" /> </property> </class> </hibernate-mapping> native代表数据库自己生成。但不同数据库的生成方式不同,比如:mysql用的是auto-increment,SQLServer用的是identity,oracle用的是序列我们定义方言时,其实也是在告诉hibernate,在属性声明为native时,如何按照不同的数据库实现赋予主键值的方式。其他很多地方也是雷同。然后,我们需要将我们添加的映射文件.hbm.xml添加到hibernate配置文件.cfg.cml中。这里我写的是目录结构路径。  Step 4.通过Hibernate API 编写访问数据库的代码这部分是Hibernate交互操作的基础。但这基础随着Hibernate的版本更迭居然还不停的变化。Hibernate的更新风格真是和Lucene那种前后版本应用代码不兼容的货越来越像了。这里我先按照填坑的脚步,把各个版本的写法都注释了:package com.happybks.hibernate.hibernatePro; import java.sql.Date; import java.sql.Timestamp; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.junit.Test; import com.happybks.hibernate.hibernatePro.beans.CuntomerBean; public class HibernateTest1 { @Test public void test1(){ //1. 创建一个SessionFactory对象 SessionFactory sessionFactory=null; //1.1 创建Configuration对象:对应包含hibernate的基本配置信息(cfg)和对象关系映射信息(hbm) Configuration configuration=new Configuration().configure(); //hibernate 3.x版本的SessionFactory的创建方式,4.X被Deprecated,5.x又再次回归。 //new Configuration().buildSessionFactory(); //1.2 创建一个ServiceRegistry对象:这个对象是从Hibernate 4.x开始新增加入的 //hibernate的任务配置和服务需要在该对象中注册后才能有效。 //hibernate 4.x版本中的ServiceRegistry创建方式:ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); //hibernate 5.x版本中的ServiceRegistry创建方式: ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build(); System.out.println(CuntomerBean.class.getCanonicalName()); Metadata metadata = new MetadataSources(serviceRegistry).addAnnotatedClass(CuntomerBean.class) .addAnnotatedClassName(CuntomerBean.class.getName()).addResource("com/happybks/hibernate/hibernatePro/beans/CuntomerBean.hbm.xml") .getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE) .build(); //1.3 创建sessionFactory //hibernate 4.x版本中的sessionFactory创建方式: sessionFactory=configuration.buildSessionFactory(serviceRegistry); //hibernate 5.x版本中的sessionFactory创建方式: sessionFactory=metadata.getSessionFactoryBuilder().build(); //2. 创建一个Session对象 Session session=sessionFactory.openSession(); //3. 开启事务 Transaction transaction=session.beginTransaction(); //4. 执行保存操作。把对象保存到数据库 CuntomerBean bean=new CuntomerBean(); bean.setName("HappyBKs"); bean.setNo(314); bean.setMoney(20688.68); bean.setScore(98765432123456789L); bean.setRegisterDate(new Date(new java.util.Date().getTime())); bean.setLoginTime(Timestamp.valueOf("2017-01-08 12:00:00")); session.save(bean); //5. 提交事务。 transaction.commit(); //6. 关闭Session session.close(); //7. 关闭SessionFactory对象。 sessionFactory.close(); } } 这里1.1的configure方法是重载的。可以自己制定配置文件。如configure()方法包含若干个重载的方法。configure(File )等能够通过指定配置文件来生成Configure对象。这里我们使用默认的hibernate.cfg.xml。所以只需要使用无参数的configure()方法即可。 我们查看configure()的源码,可以看到无参数的configure()方法就是hibernate.cfg.xml。这里插个题外话,STS的Maven设置、源代码和doc自动获取如下。以后源码什么的会自动下载到你本地的maven库。不需要你自己再下载保存整理了。 hibernate 3.x版本的SessionFactory的创建方式是new Configuration().buildSessionFactory();,4.X被Deprecated了。(这种方式在5.x又再次回归,这个最后再说。)在4版本中,配置被当做服务注册,并以此建立SessionFactory。Configuration conf = new Configuration().configure(); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(conf.getProperties()).buildServiceRegistry(); SessionFactory sf = conf.buildSessionFactory(serviceRegistry);在此种方式下,Hibernate5又进行变动了。ServiceRegistryBuilder直接没有了,真粗暴!!!!早知道这样就不要引入这个类啊,你产品经理啊,变来变去。5版本导入更换为:import org.hibernate.boot.registry.StandardServiceRegistryBuilder;好吧,我们将就用。

在5版本的Hibernate中,buildServiceReguistry()方法被替换了,用如下方法:ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();不过创建SessionFactory还需要metadata,而且这个metadata需要将类名、配置文件都需要设置了。Metadata metadata = new MetadataSources(serviceRegistry).addAnnotatedClass(CuntomerBean.class)                 .addAnnotatedClassName(CuntomerBean.class.getName()).addResource("com/happybks/hibernate/hibernatePro/beans/CuntomerBean.hbm.xml")                 .getMetadataBuilder().applyImplicitNamingStrategy(ImplicitNamingStrategyJpaCompliantImpl.INSTANCE)                 .build(); sessionFactory=metadata.getSessionFactoryBuilder().build();真要这样写出这种难以维护的代码,我宁愿用老版本了。不过这种方式是可以运行的,咱们先看完。数据库在运行之前,没有表。运行这个测试方法。日志如下,按照我们在cfg配置文件中设置的,输出SQL语句,还是格式化的那种。如下:说明运行成功了。一些提示最好要有密码什么的暂且忽略。一月 08, 2017 3:22:51 下午 org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core {5.2.5.Final} 一月 08, 2017 3:22:51 下午 org.hibernate.cfg.Environment <clinit> INFO: HHH000206: hibernate.properties not found com.happybks.hibernate.hibernatePro.beans.CuntomerBean 一月 08, 2017 3:22:52 下午 org.hibernate.boot.jaxb.internal.stax.LocalXmlResourceResolver resolveEntity WARN: HHH90000012: Recognized obsolete hibernate namespace http://hibernate.sourceforge.net/hibernate-mapping. Use namespace http://www.hibernate.org/dtd/hibernate-mapping instead. Support for obsolete DTD/XSD namespaces may be removed at any time. 一月 08, 2017 3:22:52 下午 org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations {5.0.1.Final} 一月 08, 2017 3:22:52 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!) Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary. 一月 08, 2017 3:22:52 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001005: using driver [com.mysql.jdbc.Driver] at URL [jdbc:mysql://localhost:3306/happybksdb?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false] 一月 08, 2017 3:22:52 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001001: Connection properties: {user=root, password=****} 一月 08, 2017 3:22:52 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001003: Autocommit mode: false 一月 08, 2017 3:22:52 下午 org.hibernate.engine.jdbc.connections.internal.PooledConnections <init> INFO: HHH000115: Hibernate connection pool size: 20 (min=1) 一月 08, 2017 3:22:52 下午 org.hibernate.dialect.Dialect <init> INFO: HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect 一月 08, 2017 3:22:53 下午 org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@22c01ab0] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Hibernate: create table CUNTOMERBEAN ( CID integer not null auto_increment, NAME varchar(255), NO integer, SCORE bigint, MONEY double precision, REGISTERDATE date, LOGINTIME datetime, primary key (CID) ) Hibernate: insert into CUNTOMERBEAN (NAME, NO, SCORE, MONEY, REGISTERDATE, LOGINTIME) values (?, ?, ?, ?, ?, ?) 一月 08, 2017 3:22:54 下午 org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl stop INFO: HHH10001008: Cleaning up connection pool [jdbc:mysql://localhost:3306/happybksdb?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false] 我们查看数据库,数据表已经为我们自动建立好了。(若干年前还在手写映射文件和对比数据库字段有没有检错的我泪流满面。。)我们用mysql bench的生成一份建表语句,看看表的定义,与hbm映射文件中的定义字段完全一样,主键也按照设置的native,通过自己的方言,构建了属于mysql的方式:自增。(oracle和postgresql是建序列)CREATE TABLE `cuntomerbean` ( `CID` int(11) NOT NULL AUTO_INCREMENT, `NAME` varchar(255) DEFAULT NULL, `NO` int(11) DEFAULT NULL, `SCORE` bigint(20) DEFAULT NULL, `MONEY` double DEFAULT NULL, `REGISTERDATE` date DEFAULT NULL, `LOGINTIME` datetime DEFAULT NULL, PRIMARY KEY (`CID`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; 查看表的记录,已经有了:好吧,回到刚才的问题。这的要用metadata这种方式吗。我前面已经说了,configuration.buildSessionFactory()方法在hibernate3中被广泛使用;在4.x中被不推荐;到了5.X又回来了。我们还是用这种方式吧。package com.happybks.hibernate.hibernatePro; import java.sql.Date; import java.sql.Timestamp; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; import org.junit.Test; import com.happybks.hibernate.hibernatePro.beans.CuntomerBean; public class HibernateTest1 { @Test public void test1(){ //1. 创建一个SessionFactory对象 SessionFactory sessionFactory=null; //1.1 创建Configuration对象:对应包含hibernate的基本配置信息(cfg)和对象关系映射信息(hbm) Configuration configuration=new Configuration().configure(); sessionFactory=configuration.buildSessionFactory(); //2. 创建一个Session对象 Session session=sessionFactory.openSession(); //3. 开启事务 Transaction transaction=session.beginTransaction(); //4. 执行保存操作。把对象保存到数据库 CuntomerBean bean=new CuntomerBean(); bean.setName("HappyBKs"); bean.setNo(314); bean.setMoney(20688.68); bean.setScore(98765432123456789L); bean.setRegisterDate(new Date(new java.util.Date().getTime())); bean.setLoginTime(Timestamp.valueOf("2017-01-08 12:00:00")); session.save(bean); //5. 提交事务。 transaction.commit(); //6. 关闭Session session.close(); //7. 关闭SessionFactory对象。 sessionFactory.close(); } }

相关内容推荐