在准备整合Spring之前,也在网上看了各种配置。但是楼主心里还是很纠结,为啥一定要配置事务。配事务就配事务为啥要配拦截,配拦截就配拦截为啥要配自动代理。都是因为楼主是java菜鸟。不然这些肯定是java方面的常识而已。楼主还是一步一步的来吧,感觉Spring操作Hibernate还是离不开DataSource,SessionFactory,Transaction这几个要素。
配置pom.xml添加需要的jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
一个是Spring管理Hibernate的Jar包,一个是记录日志的log4jar包。其他配置就不列出了,之前文章中有提到。本来c3p0这个jar包也是可以通过配置pom.xml下载。可是楼主配置了,也下载了,但是看不到里面类的定义,只能另外下载再包含到项目中。
配置数据源Bean(db_connection.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd">
<bean id="datasource" name="datasource"
class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.microsoft.sqlserver.jdbc.SQLServerDriver">
</property>
<property name="password" value="123123"></property>
<property name="user" value="sa"></property>
<property name="jdbcUrl"
value="jdbc:sqlserver://localhost:1433;databaseName=test">
</property>
</bean>
</beans>
使用c3p0这个jar包中的Api来操作数据源。至于其他操作数据库的API哪个支持连接池,哪个效率高,楼主没去研究,楼主只想能操作到数据库就行。
配置SessionFactory(application.xml)
<bean id="sessionFactory" name="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="datasource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.SQLServerDialect
</prop>
</props>
</property>
<property name="mappingDirectoryLocations">
<list>
<value>classpath:com/hurricane/entity</value>
</list>
</property>
</bean>
LocalSessionFactoryBean类继承了hibernate的SessionFactory,至此SessionFactory和DataSource都华丽丽出现了。
折腾中。。。
想着既然SessionFactory有了,楼主调用下Save方法看看能不能成功。于是创建了个DAL类,代码如下:
package com.hurricane.dal;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.orm.hibernate5.support.HibernateDaoSupport;
import com.hurricane.entity.Person;
public class PersonDAL extends HibernateDaoSupport {
public int SavePerson(Person person)
{
this.getHibernateTemplate().save(person);
return 1;
}
}
很期待的跑起来,结果结果很残忍:
Struts Problem Report
Struts has detected an unhandled exception:
Messages: •Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
File: org/springframework/orm/hibernate5/HibernateTemplate.java
Line number: 1,132
试了下原生的调用方式:
public class PersonDAL extends HibernateDaoSupport {
public int SavePerson(Person person)
{
Session ss = this.getSessionFactory().openSession();
ss.beginTransaction();
ss.save(person);
ss.getTransaction().commit();
ss.close();
return 1;
}
}
可以,没有问题,但是这个不算spring操作hibernate的正确打开方式吧。既然都让spring管理hibernate了,就放手吧。
于是网上各种查配置:
1.Web.xml中配置OpenSessionInViewFilter
这个类在hibernate5中已经没有FlushMode的设置了,所以不好使。
2.配置Spring事务管理。
为啥一定要配置事务。楼主还是不死心啊,于是觉得调试到源码里面看看。
Session session = null;
boolean isNew = false;
try {
session = getSessionFactory().getCurrentSession();
}
catch (HibernateException ex) {
logger.debug("Could not retrieve pre-bound Hibernate session", ex);
}
if (session == null) {
session = getSessionFactory().openSession();
session.setFlushMode(FlushMode.MANUAL);
isNew = true;
}
这段源码显示如果获取不到当前环境的Session,新创建的Session打开方式就是Manual的。但是为什么获取不到当前环境的Session。跟踪下去,发现getResource方法获取不到资源。有get肯定要有set才能get到吧。看了下有个bindResource,看方法注视“将给定的资源绑定到当前线程”,可是根本没进到这个方法,看下引用的地方,还不少。有两个bindResource的地方引起我的注意:
1.OpenSessionInViewFilter(但是hibernate5没有flushmode这个属性让设置),默认的还是manual.
2.HibernateTransactionManager
HibernateTransactionManager是个设置FlushMode的入口。先配置下看看。
配置TransactionManager
<bean id="transManager" name="transManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
配置这个事务管理bean的时候,楼主心里好多疑问。配置了之后怎么beginTransaction,怎么CommitTransaction,怎么rollback啊。
配置TransactionInterceptor
<bean id="transinterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transManager">
</property>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
拦截,就是创建代理在调用方法前后插入想要执行的代码,看过拦截器的大概知道一二。如果是数据库的事务调用hibernate的transactionmanger管理事务;如果是程序的事务就调用程序的事务管理,有异常就回滚。
配置AutoProxyCreator
<bean id="proxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>personDAl</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transinterceptor</value>
</list>
</property>
</bean>
自动创建代理类,这个地方楼主也好好奇。怎么我调用的是DAL类,会自动调用它代理类。既然Spring自动创建了这些类,当然也能区分哪些是需要调用代理类的吧。
运行
这里省略。