一、基本配置
在Spring的servlet-context.xml文件中添加
<!-- 配置数据库 --> <!-- 简单的使用jdbc的DriverManagerDataSource,没有连接池 --> <beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <beans:property name="driverClassName" value="com.mysql.jdbc.Driver" /> <beans:property name="url" value="jdbc:mysql://localhost:3306/your_database" /> <beans:property name="username" value="your_name" /> <beans:property name="password" value="your_password" /> </beans:bean> <!-- 配置hibernate的session factory --> <beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <beans:property name="dataSource" ref="dataSource" /> <!-- 定义去哪些包下扫描实体类(@Entity注解) --> <beans:property name="packagesToScan"> <beans:list> <!-- 可以加多个包 --> <beans:value>com.funway.mybet.model</beans:value> </beans:list> </beans:property> <beans:property name="hibernateProperties"> <beans:props> <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</beans:prop> <beans:prop key="hibernate.show_sql">true</beans:prop> <beans:prop key="hibernate.format_sql">true</beans:prop> <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop> </beans:props> </beans:property> </beans:bean>
然后如果没有Lib的话,我们需要在maven的pom.xml配置文件中添加如下几个dependency,来自动添加hibernate所需要的库。
然后定义一个获取User的Dao(暂时,我们不考虑User实体类,以及它与数据库User表的映射关系,只考虑从User表中获取用户数)
@Repository public class UserDaoHibernate { @Autowired private SessionFactory sessionFactory; public int getUserCounts() { Session session = sessionFactory.openSession(); Query query = (Query) session.createSQLQuery("select count(*) from mb_user"); int counts = Integer.parseInt(query.list().get(0).toString()); session.close(); return counts; } }
上面,我们使用@Repository注解声明自动生成一个UserDaoHibernate类型的实例对象,用@Autowired注解将servlet-context.xml中定义的sessionFactory注入到成员属性中。
然后,我们就可以在任意地方调用这个UserDaoHibernate实例的getUserCounts( )方法了。以一个Controller为例:
@Controller public class HomeController { @Autowired private UserDaoHibernate userDao; /** * ...省略 **/ @RequestMapping(value="/hiber", produces = "text/plain;charset=UTF-8") public @ResponseBody String testJdbcTemplate() { return "已注册用户数: " + userDao.getUserCounts(); }
二、使用xml配置的声明式事务
上面的getUserCounts()方法中,我们手动打开session,进行查询,最后再手动关闭session,并没有用到事务的概念。当然,简单的查询用户数量确实并不需要事务,但下面仍以这个方法为例,在getUserCounts上添加事务管理。
首先,我们先修改下getUserCounts()方法的实现:
public int getUserCounts() { Session session = sessionFactory.getCurrentSession(); Query query = (Query) session.createSQLQuery("select count(*) from mb_user"); int counts = Integer.parseInt(query.list().get(0).toString()); return counts; }
这里使用了getCurrentSession()来获取一个数据库会话。这个方法的实现是与事务相关的,如果不在Spring的xml文件中添加事务管理的配置,直接调用修改后的getUserCounts()方法的话,程序将会报错:
Could not obtain transaction-synchronized Session for current thread
<!-- 配置hibernate的事务管理器 --> <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <beans:property name="sessionFactory" ref="sessionFactory" /> </beans:bean> <!-- 定义事务策略,transaction-manager指定事务管理器为transactionManager --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <aop:config> <!-- 定义AOP通知器,连接切点与事务策略 --> <aop:advisor pointcut="execution(* com.funway.mybet.model.UserDaoHibernate.getUserCounts(..))" advice-ref="txAdvice"/> </aop:config>
同时,还需要在该xml文件的开头加上tx跟aop命名空间。
另外由于使用了Spring AOP,因此还要为程序添加如下两个依赖库
通过上面的配置,UserDaoHibernate.getUserCounts()方法就被事务管理器transactionManager包裹进来了。然后在方法执行前,transactionManager会自动去打开一个session,这样,方法中的getCurrentSession才能得到当前会话,最后在方法结束后transactionManager会自动commit并且关闭这个session,如果方法出错了,就会自动rollback。这叫做声明式事务。(当然,也可以在getUserCounts()的代码中自行管理事务,那样就叫做编程式事务)
PS:上面只是做了一个不实用的例子,在实际三层架构的项目中,并不推荐在Dao层使用事务。Dao层只实现基本的CURD(Create/Update/Read/Delete),更复杂的业务应该放在Service层。比如订单业务,Service层有一个order方法,该方法里面调用了Dao层的两个方法,一个是生成订单,insert到数据库的订单表;一个是更新库存,update数据库的库存表。那么事务就应该切入到Service层的order方法中。而不是在Dao层。
因此,事务应该切入在Service层的方法中。
三、使用@Transactional注解的声明式事务
在要声明为一个事务的getUserCounts()上面使用@Transactional注解:
@Transactional public int getUserCounts() { Session session = sessionFactory.getCurrentSession(); Query query = (Query) session.createSQLQuery("select count(*) from mb_user"); int counts = Integer.parseInt(query.list().get(0).toString()); return counts;
然后修改servlet-context.xml中定义的关于事务的配置
<!-- 配置hibernate的事务管理器,这个有什么用? --> <beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <beans:property name="sessionFactory" ref="sessionFactory" /> </beans:bean> <!-- 启动基于注解的事务 --> <tx:annotation-driven />
<tx:annotation-driven>元素告诉Spring检查上下文中所有的Bean并找到使用@Transactional注解的Bean(@Transactional可以注解在类上级别,也可以注解在方法级别)。对于每个使用了@Transactional注解的Bean,自动添加AOP事务通知器。
另外,可以使用transaction-manager属性为<tx:annotation-driven>指定特定的事务管理器(该属性默认值即为”transactionManager”,所以上面的例子中我们无需特别指定)
<tx:annotation-driven transaction-manager=”txManager” />
使用@Transactional注解,就可以无需在xml文件中定义繁琐的AOP切面以及事务策略了。
四、写入Mysql后中文为??的问题
被各种中文乱码伤透心 =。=#
要把jdbc的url配置改为如下:
<beans:property name=”url” value=”jdbc:mysql://localhost:3306/mybet?useUnicode=true&characterEncoding=UTF-8″ />
注意,由于配置文件是xml格式,所以userUnicode与characterEncoding中间的&符号应该用其对应的转义字符&否则eclipse的xml检查会报错。