一、JavaProject配置过程(TestHibernate)
1、加入Hibernate支持,即拷贝Hibernate支持jar包;创建hiberante.cfg.xml文件。(注解配置方式)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//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:3306/bbs_db</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- 方言dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 是否显示sql语句 -->
<property name="show_sql">true</property>
<!-- 数据库更新方式 -->
<property name="hbm2ddl.auto">update</property>
<!-- 实体关系映射 -->
<mapping class="com.bbs.bean.User"/>
</session-factory>
</hibernate-configuration>
2、创建持久化类Admin、User等,并通过注解配置“实体关系映射”。(重点)
- 涉及多个知识点,如:
@Many To One
映射关系,@One To Many
等。(重点) - @GeneratedValue主键生成策略,常用
strategy = GenerationType.AUTO
(重点) - fetch=FetchType.LAZY懒加载设置及级联配置cascade设置。(重点)(此处为系统设计部分,初级工程师先关注具体使用。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package com.bbs.bean;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
// 用户注册实体类,对应t_user表
@Entity
@Table(name = "t_user")
public class User {
private int userid;
private String username;
private String password;
private String sex;
private String hobbys;
private String birthday;
private String city;
private String email;
private String qq;
private String createtime;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getUserid() {
return userid;
}
@Column(name = "username")
public String getUsername() {
return username;
}
@Column(name = "password")
public String getPassword() {
return password;
}
@Column(name = "sex")
public String getSex() {
return sex;
}
@Column(name = "hobbys")
public String getHobbys() {
return hobbys;
}
@Column(name = "birthday")
public String getBirthday() {
return birthday;
}
@Column(name = "city")
public String getCity() {
return city;
}
@Column(name = "email")
public String getEmail() {
return email;
}
@Column(name = "qq")
public String getQq() {
return qq;
}
@Column(name = "createtime")
public String getCreatetime() {
return createtime;
}
public void setUserid(int userid) {
this.userid = userid;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setHobbys(String hobbys) {
this.hobbys = hobbys;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
public void setCity(String city) {
this.city = city;
}
public void setEmail(String email) {
this.email = email;
}
public void setQq(String qq) {
this.qq = qq;
}
public void setCreatetime(String createtime) {
this.createtime = createtime;
}
}
3、JavaProject工程项目下,需要通过工厂类,获取session对象:(代码片段)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.bbs.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;
/**
* 自定义工厂类 单例模式
* Hibernate五大核心接口
* configuration接口、
* sessionFactory接口、
* session接口、
* Transaction接口、
* query接口
*/
public class MySessionFactory {
/**
* 1.设置私有的构造函数
* 2.定义一个静态变量
* 3.定义一段静态代码块
* 4.定义一个方法用于获取单例模式对象
* 5.单例模式分为饿汉模式和懒汉模式两种
*/
private static SessionFactory sessionFactory;
static {
// 使用configuration接口获取hibernate配置文件 /hibernate.cfg.xml"
// 第一种读取注解,第二种关系映射配置文件形式
Configuration configuration = new AnnotationConfiguration();
configuration.configure("hibernate.cfg.xml");
// 获取工厂类
if (sessionFactory == null) {
sessionFactory = configuration.buildSessionFactory();
}
}
// 单例模式下具有一个私有的构造函数
private MySessionFactory() {
}
// 该方法用于获取工厂类
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
4、调用HibernateAPI五大接口,SessionFactory、Session、Transaction,完成对象持久化过程,即保存操作。
1
2
3
4
5
6
7
8
9
10
11
12
SessionFactory factory = MySessionFactory.getSessionFactory();
Session session = factory.openSession();
// 开启事务
session.beginTransaction();
Admin admin = new Admin();
admin.setAdminname("zhangsan");
admin.setAdminpassword("123456");
// 临时状态(瞬时状态)Transient
session.save(admin);
// 提交事务
session.getTransaction().commit();
session.close();
及Query接口,HQL语句执行。
1
2
3
4
Session session = factory.openSession();
Query q = session.createQuery("from Admin e where e.adminid=:id");
q.setInteger("id", 1);
session.close();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.bbs.test;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.bbs.bean.User;
import com.bbs.util.MySessionFactory;
public class TestOpenSession {
public static void main(String[] args) {
SessionFactory factory = MySessionFactory.getSessionFactory();
Session session = factory.openSession();
// 开启事务
session.beginTransaction();
// 临时对象
User user = new User();
user.setCreatetime("1995-15-15");
user.setPassword("123");
user.setSex("1");
user.setUsername("zhong");
// 临时状态
// 持久化过程就是一个数据保存的过程
session.save(user);
// 提交事务
session.getTransaction().commit();
session.close();
//执行HQL语句
Session session1 = factory.openSession();
Query q = session1.createQuery("from User u where u.userid=:id");
q.setInteger("id", 8);
User user1 = (User) session1.get(User.class, 8);
System.out.println("1." + ((User)(q.list().get(0))).getUsername());
System.out.println("2." + user1.getUsername());
session1.close();
}
}
二、真实项目使用情况(TestHibernate1)
对以上项目架构做分析,其中factory.openSession()
的使用,在实际项目中,每次访问都产生一个session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session(每次都需要关闭;增加服务器负担),所以,我们通常使用factory.getCurrentSession
,从字面上可以看得出来,是获取当前上下文一个session对象,当第一次使用此方法时,会自动产生一个session对象,并且连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一,简单而言,getCurrentSession就是,如果有已经使用的,用旧的,如果没有,建新的。getCurrentSession是在事务提交时自动调用close方法。实际项目中,我们选择使用getCurrentSession,并且此方法的使用,必须开启事务。使用SessionFactory.getCurrentSession()
需要在hibernate.cfg.xml中如下配置:
-
如果采用jdbc独立引用程序配置如下
1
<property name="hibernate.current_session_context_class">thread</property>
-
如果采用了JTA事务配置如下
1
<property name="hibernate.current_session_context_class">jta</property>
具体使用步骤,如下:
-
需要上下文配置(即在hibernate.cfg.xml)中,需要配置
1
<property name="current_session_context_class">thread</property>
-
代码如下
1 2 3 4 5 6 7 8
// 必须加入事务,线程安全 Session session = factory.getCurrentSession(); // 开启事务 session.beginTransaction(); Message e = (Message) session.get(Message.calss, 39); // 提交 自动close session.getTransaction().commit();
小提示:事务的处理,可以通过动态代理简化代码量,并可统一管理。
在实际项目中,我们还需要考虑数据库访问时效性。需要使用“JDBC连接池”。我们选择C3P0,具体配置如下,同时导入C3P0的jar包支持:
1
2
<!-- 连接池Jdbc connection pool C3P0 -->
<property name="connection.pool_size">1</property>
三、WebProject配置过程(TestSH1.1&TestSH1.2)
Hibernate的使用我们在JavaProject中已经充分展示了;在WebProject项目中,使用Hibernate的方式和Java项目中没有太多区别。我们在实际项目中,是通过Spring整合Hibernate的方式集成使用;总体来说写的代码绝对比单独用Hibernate然后在DAO类里写的代码要少;使用Spring整合Hibernate,配置较多。
使用getCurrentSession,所有的操作都必须开启事务,所以需要我们注意,使用Spring框架的声明式事务,不再需要自动创建sessionFactory和session,不再需要手动控制事务的开启和关闭。(重点)
具体实现步骤如下:
- 在Spirng配置文件中,装配一个
org.springframework.orm.hibernate3.LocalSessionFactoryBean
类。- 方法一、配置数据源,读取配置文件,获取连接信息;设置hibernate配置信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
<bean id="dataSource" destory-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="annotatedClasses"> <list> <value>com.hp.model.User</value> <value>com.hp.model.Log</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.OracleDialect <prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean>
或者hibernate3版本的AnnotationSessionFactoryBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <!-- 加入事务,就不需要此处配置 --> <prop key="hibernate.current_session_context_class">thread</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> <property name="packagesToScan"> <list> <value>com.bbs.bean</value> </list> </property> </bean>
-
方法二、可以通过configLocation属性,加载hibernate.cfg.xml文件。
1 2 3 4 5
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="configLocation" value="file:src/hibernate.cfg.xml"> </property> </bean>
1
2. 在spring环境下,新建一个操作类TestSpringDao,需要继承HibernateDaoSupport。
1 2 3 4 5 6
public void test1() { Session session = this.getSessionFactory().getCurrentSession(); session.beginTransaction(); Message e = (Message) session.get(Message.class, 35); session.getTransaction().commit(); }
-
在spring配置文件中,装配一个bean,必须注入属性sessioniFactory值。
1 2 3 4 5
<bean id="testDao1" class="com.bbs.test.TestSpringDao"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean>
-
单元测试,此时可以获取Message对象,才成功。
1 2 3 4 5
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 如何获取类的实例 TestSpringDao dao1 = (TestSpringDao) ac.getBean("testDao1"); dao1.test1();
四、实际项目使用(TestSH2)
在Spring整合Hibernate框架中,方法中需要开启事务,以及提交事务。这部分代码基本都是模板化的,那么,我们如何在编写过程中把这部分代码省略,或者让系统自动为我们添加。这时,我们考虑到动态代理模式及SpringAOP。我们在实际项目中是如何做的?demo演示如下,在实际项目中我们选择Spring3.0及Hibernate3.0,我们选择注解的形式:
-
首先从配置文件开始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
<!-- apache下的BasicDataSource,数据库连接池 --> <bean id="dataSource" destory-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> </property> <property name="url" value="${jdbc.url}"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </prop> <!-- 加入事务,就不需要此处配置 --> <prop key="hibernate.current_session_context_class">thread</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> <property name="packagesToScan"> <list> <value>com.bbs.bean</value> </list> </property </bean>
-
设计dao层具体实现:
按照MVC的设计思想,我们创建UserDao层,com.bbs.dao.impl,创建类UserDaoImpl,继承HibernateDaoSupport,这个类是Spring框架提供的,我们使用其中的getHibernateTemplate方法(其中还有一个getSession方法,不常用),getHibernateTemplate方法提供非常多的常用方法来完成基本的操作。而getSession方法是没有经过Spring包装的,Spring会把最原始的Session给你,在使用完之后必须自己调用相应的close方法,而且也不会对声明式事务进行相应的管理,一旦没有及时关闭连接,就会导致数据库连接池的连接数溢出;getHibernateTemplate()方法是经过Spring封装的,例如添加相应的声明式事务管理,由Spring管理相应的连接。
在实际的使用过程中发现的确getHibernateTemplate()比getSession()方法要好很多,但是有些方法在getHibernateTemplate()并没有提供,这时我们用HibernateCallback回调的方法操作数据库(比如对原生sql语句的执行)。
继承HibernateDaoSupport是可以的,但这种方式还是不太好,还是用到了继承,也就是没有降低所谓的耦合度。解决方案:
-
Spring为我们提供了一个hibernateTemplate,你只需在配置文件中配置一个bean,并传入一个sessionFactory。
1 2 3 4
<bean id="hibernateTemplate" class="com.springframework.orm.hibernate3.HibernateTemplate"> <property name="sessionFactory" ref="sessionFactory"/> </bean>
-
然后在使用dao的时候注入该hibernateTemplate的bean即可。通过注解实现,因此
@Component
相当于<bean id="" class=""/>
1 2 3 4 5 6 7 8 9 10 11 12 13
@Component public class UserDaoImpl implements UserDao { @Autowired private HibernateTemplate hibernateTemplate; public HibernateTemplate getHibernateTemplate() { return hibernateTemplate; } public void setHibernateTemplate(HibernateTemplate hibernateTemplate) { this.hibernateTemplate = hibernateTemplate; } }
-
在方法中直接使用hibernateTemplate提供的get、load、find等方法。
-
- 事务管理,Spring提供的事务管理可以分为两类:编程式、声明式,编程式,其实就是在代码里面来控制,像Hibernate操作数据一样,开启事务,提交事务,这种方式有一定的局限性,所以我们一般是用声明式来配置我们的事务。在Spring和Hibernate整合架构中,声明式事务配置,包括以下三项:
- 事务管理类,我们选择DataSourceTransactionManager或HibernateTransactionManager;
- 以及声明式事务隔离级别及传播特性,我们通过advice通知拦截;(其中包括五部分,重点,难点)
传播行为
隔离级别 isolation=”default”1 2
<tx:method name="add" propagation="REQUIRED" isolation="default" read-only="false"/>
只读 read-only=”false”
事务超时 timeout=”-1”1
<tx:method name="add" timeout="-1">
回滚规则 rollback-for=”” / no-rollback-for=””
1
<tx:method name="update" no-rollback-for="">
- 以及哪些类和方法参与事务,我们通过SpringAOP实现。
经过以上配置,我们可以实现特定的业务,执行不同的事务策略。程序员只需要关心业务代码实现即可,极大的减轻了程序员额外代码。当然,事务切入点,我们是在sevice层去配置。
-
Spring配置中定义扫描器,把这些类,纳入Spring容器管理中。
1 2
<!-- 扫描注解类 --> <context:component-scan base-package="com.bbs"/>
-
至此,我们的整合工作就基本完成了。我们可以通过一个单元测试,验证一下:
1 2 3 4 5 6
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); // 如何获取类的实例 UserDao dao1 = (UserDao) ac.getBean("userDaoImpl"); User user = dao1.findUserById(9); System.out.println(user.getUsername());
-
业务层service改造,及注解实现:
- @Service用于标注业务层组件,即service层类
- @Controller用于标注控制层组件(如spingMVC中的控制类)
- @Repository用于标注数据访问组件,即dao层类
-
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
1 2 3 4 5 6 7 8 9 10 11 12 13
@Service public class UserService implements IuserService { @Autowired private IUserDao userDao; public IUserDao getUserDao() { return userDao; } public void setUserDao(IUserDao userDao) { this.userDao = userDao; } }
-
控制层改造及实现,及代码片段:使用@controller注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@Controller public class LoginServlet { @Autowired IUserService userService; public IUserService getUserService() { return userService; } public void setUserService(IUserService userService) { this.userService = uerService; } @RequestMapping(value="login", method=RequestMethod.POST) }
五、BBS论坛项目,升级为SpringMVC3.0 + Hibernate3.0 + Mysql5.1 + DBCP数据源项目,升级项目名SH_BBSV4.0
具体实现步骤,参考以为配置。
六、Hibernate二级缓存
- 一级缓存及Session缓存,是事务级别的,由Hibernate去管理,一般不去干涉。
- 二级缓存是sessionFactroy缓存,我们可以根据业务访问及修改频次去设置缓存级别,及设置缓存文字。