Hibernate 基本使用
在应用程序中使用 Hibernate 框架的基本步骤如下:
1)将 Hibernate 相关依赖库导入项目中(详见
http://blog.csdn.net/al_assad/article/details/77887263
);
2)创建POJO(持久化实体)类,对于数据库中某个表映射为实体;
3)创建配置文件(
hibernate.cfg.xml
),配置 数据库连接参数,选用数据库引擎 等的配置;
4)创建检索或存储持久对象的类(实际使用POJO的逻辑类);
※ 其中对于 POJO 的配置推荐使用注解进行配置,当然也可以使用该POJO独立的xml配置进行配置,但是这种方法会减低项目的可维护性,所以还是推荐使用直接在 POJO 中进行注解配置;
简单示例
以下结合一个简单示例, 来讲解各个步骤,示例说明 :
本示例使用的 hibernate 版本为 5.2;
使用的数据库为 MySQL 5.5;
数据库名“ioganes“,使用其中的 ”users“数据表作为示例,结构如下:
由于 Hibernate 底层使用 JDBC 连接数据库,所以项目依赖中要导入 mysql-connector-java.jar,下载地址:
https://dev.mysql.com/downloads/connector/j/
工程结构示意:
1)持久化实体类 POJO
demo.Users.java
package demo;
import javax.persistence.*;
import java.util.Date;
@Entity
@Table(name="users")
public class Users {
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="user_id")
private int id;
@Column(name="user_name")
private String name;
@Column(name="user_password")
private String password;
@Column(name="create_date")
@Temporal(TemporalType.DATE)
private Date createDate;
@Column(name="user_icon")
private String icon;
//省略所有属性的 get、set方法
}
持久化实体类(PO)类本身是一个持久化JavaBean(POJO),用于映射关系型数据库中的某个表单的数据为类对象,在POJO中使用相应的持久化注解用于标注各项持久化标注;
在新版本的hibernate中,提倡使用持久化注解来代替传统的持久化映射配置文件,这样可以增强代码的可读性;
以下是以上示例中出现的标注的解释:
@Entity :声明该类是一个 Hibernate 持久化实体(PO);
@Table:指定该类映射的表,此处映射到 users 表;
@Id: 指定该类的标识属性,即可以唯一标识该类的属性,通常映射到数据表的主键字段;
@GeneratedValue:指定主键的生成策略,这里strategy属性指定为
IDENTITY,即自动增长的主键生成策略,关于这部分详见下;
@Column:指定该类属性映射到数据表的相应字段名(不设置默认使用该属性名称);
完整的持久化注解可以参考:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html
2)配置文件
hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--设置数据库连接参数-->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property> <!--连接数据库的驱动-->
<property name="connection.url">jdbc:mysql://localhost/iogames</property> <!--连接数据库的URL-->
<property name="connection.username">root</property> <!--连接数据库的用户名-->
<property name="connection.password">mysql1994assad</property> <!--连接数据库的密码-->
<!--设置C3P0数据源参数-->
<property name="hibernate.c3p0.max_size">20</property> <!--连接池的最大连接数-->
<property name="hibernate.c3p0.min_size">1</property> <!--连接池的最大连接数-->
<property name="hibernate.c3p0.timeout">5000</property> <!--连接池里连接的超时时长-->
<property name="hibernate.c3p0.max_statements">100</property> <!--连接池最大缓存存放statement数量-->
<property name="hibernate.c3p0.idle_test_period">3000</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.validate">true</property>
<!--设置数据库方言,本示例中使用 mysql5.5 方言-->
<property name="dialect">org.hibernate.dialect.MySQL55Dialect</property>
<!--根据需要自动创建数据库-->
<property name="hbm2ddl.auto">update</property>
<!--显示 hibernate 持久化操作所生成的 SQL-->
<property name="show_sql">true</property>
<!--将 SQL 脚本格式化后再输出-->
<property name="hibernate.format_sql">true</property>
<!--罗列所有的 POJO 持久化类名-->
<mapping class="demo.Users" />
</session-factory>
</hibernate-configuration>
hibernate.cfg.xml 配置文件用于配置数据库连接映射等信息的配置文件,默认放置在项目src目录下,默认命名为"
hibernate.cfg.xml
",当运行构造上下文对象时,会自动调用该文件(当然也可以显式调用),当项目存在调用多个数据库时,可以将其使用多个映射配置文件,在构造上下文对象时显式调用相应文件即可;
以上的配置文件使用了 Hibernate 推荐的 c3p0 数据源代替传统的 DriverManager 来连接数据库,有助于保证最好的的数据库连接性能;
更多详细的数据库配置文件参数可以参见:
http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#database
3)操作类
demo.UserManager.java
package demo;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import java.util.Date;
public class UserManager {
public static void main(String[] args){
//根据配置文件创建连接注册对象
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
//以连接注册对象创建 SessionFactory 对象
SessionFactory sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
try{
//创建一个Session会话对象
Session session = sessionFactory.openSession();
//开始事务
Transaction tran = session.beginTransaction();
//创建一个Users对象,这部分为实际的数据库CRDU操作区域
Users user = new Users();
user.setName("Al-assad");
user.setPassword("123");
user.setCreateDate(new Date());
user.setIcon("1");
//会话对象保存User,事务提交
session.save(user);
tran.commit();
//关闭 Session、 SessionFactory 连接
session.close();
sessionFactory.close();
}catch(Exception ex){
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
其中关于 Sessionfactory,Session,Transaction 等主要数据库操作对象的解释,可以参见:
http://blog.csdn.net/al_assad/article/details/77887263
- 结构体系
对于以上代码的优化,可以拆分出一个 HibernateUtil 专门用管理Session,如下:
HibernateUtil.java
import org.hibernate.*;
import org.hibernate.service.*;
import org.hibernate.boot.registry.*;
import org.hibernate.cfg.*;
public class HibernateUtil{
public static SessionFactory sessionFactory;
static{
try{
//根据配置文件创建连接注册对象
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure("hibernate.cfg.xml")
.build();
//以连接注册对象创建 SessionFactory 对象
sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
}catch (Throwable ex){
throw new ExceptionInInitializerError(ex);
}
}
// ThreadLocal可以隔离多个线程的数据共享,因此不再需要对线程同步
public static final ThreadLocal<Session> session = new ThreadLocal<Session>();
public static Session currentSession() throws HibernateException{
Session s = session.get();
// 如果该线程还没有Session,则创建一个新的Session
if (s == null){
s = sessionFactory.openSession();
// 将获得的Session变量存储在ThreadLocal变量session里
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException{
Session s = session.get();
if (s != null)
s.close();
session.set(null);
}
}
UserManager.java
public class UserManager {
public static void main(String[] args){
//创建一个Session会话对象
Session session = HibernateUitl.currentSession();
//开始事务
Transaction tran = session.beginTransaction();
//创建一个Users对象,这部分为实际的数据库CRDU操作区域
Users user = new Users();
user.setName("Al-assad");
user.setPassword("123");
user.setCreateDate(new Date());
user.setIcon("1");
//会话对象保存User,事务提交
session.save(user);
tran.commit();
//关闭Session
SessionUtil.closeSession();
}
}
持久化对象操作
持久化对象的状态
实际使用持久化对象 PO 过程中,要先获取 Session 对象,POJO 只有在 Session 的管理下才能完成对数据库的访问,PO 与 Session 的关联关系有以下3种:
- 瞬态:PO 实例与 Session 从未关联过,此事 PO 实例处于瞬态;
- 持久化:PO 实例与 Session 关联起来,该示例对应到数据库记录,则该实例处于持久化态;
- 脱管态:PO 实例曾经与 Session 关联过,但是由于 Session 关闭等原因,PO 实例脱离了 Session 的托管,此时该实例处于脱管态;
改变持久化对象状态的方法
① 持久化实体
将瞬态对象转变为持久化对象,使用 Session 对象的 save(), persist() 方法;
Users user = new User(); user.setName("assad"); session.save(user);
②根据主键加载持久化实体
可以通过Session 的 get() ,load() 方法根据主键加载一个实体,不同的是如果指定主键的实体不存在,get返回null,load抛出一个HibernateException;
User user = session.get(User.class,"20140302");
③更新持久化实体
User user = session.get(User.class,"20140302"); user.setName("assad"); session.flush();
④更新托管主体
对于一个已经脱离了 Session 管理的实体,当程序修改了托管对象的状态后,需要显式地使用新的 Session 来保存这些修改,可以使用 Session 对象的 update(),merge(),updateOrSave() 方法进行保存修改的实体;
update 方法会直接将该对象持久化,如果该对象曾经实体化过,使用update,如果没有,使用save,不确定时,使用 updateOrSave;
merge 方法区别于 update,不会直接持久化该对象,而是向将该对象拷贝一个副本,将该副本持久化,但是原来的对象不持久化,也不重新关联Session;
Session sess1 = sessionFactory.openSession(); User user = sess1.get(User.class,"20140302"); sess1.close(); user.setName("assad"); Session sess2 = sessionFactory.openSession(); sess2.update(user);
⑤删除持久化实体可以使用 Session 的 delete 方法删除持久化实体,一旦删除该持久化实体,其对应的数据表记录也会被删除;
User user = session.get(User.class,"20140302"); session.delete(user);
事务操作
Hibernate 的事务操作是通过对 Session 对象的 Transaction 对象来实现的;事务的提交
public static void main(String[] args){
Session session = HibernateUitl.currentSession();
Transaction tran = session.beginTransaction(); //开始事务
//CRUD操作
Users user = new Users();
user.setName("Al-assad");
user.setPassword("123");
session.save(user);
tran.commit(); //事务提交
SessionUtil.closeSession();
}
事务的回滚
public static void main(String[] args){
Session session = HibernateUitl.currentSession();
Transaction tran = session.beginTransaction(); //开始事务
//CRUD操作
Users user = new Users();
user.setName("Al-assad");
user.setPassword("123");
if(flag) { //回滚条件
tran.rollback(); //事务回滚
}
session.save(user);
tran.commit(); //事务提交
SessionUtil.closeSession();
}
关于 Transaction 的更多用法,包括设置超时、获取 transaction 状态等,参见:
http://docs.jboss.org/hibernate/orm/5.2/javadocs/