完成例子:spring容器中取出业务bean,传入参数用户信息,持久化到数据库.
1.新建工程,导入spring包和hibernate包,还需要mysql驱动包,为方便测试,还导入junit包.
2.业务层类与dao层
package com.skymr.sphi.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.skymr.sphi.model.User;
public class UserDao {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(User user){
System.out.println("执行UserDao save方法:");
Session session = sessionFactory.openSession();
Transaction tran = session.beginTransaction();
session.save(user);
tran.commit();
session.close();
}
public void update(User user){
System.out.println("执行UserDao update方法:");
Session session = sessionFactory.openSession();
Transaction tran = session.beginTransaction();
session.update(user);
tran.commit();
session.close();
}
public void delete(int id){
System.out.println("执行UserDao delete方法:");
Session session = sessionFactory.openSession();
Transaction tran = session.beginTransaction();
session.delete(id);
tran.commit();
session.close();
}
public User query(int id){
System.out.println("执行UserDao query方法:");
Session session = sessionFactory.openSession();
User ret = (User)session.get(User.class, id);
session.close();
return ret;
}
}
package com.skymr.sphi.service;
import com.skymr.sphi.model.User;
public interface UserService {
//保存用户信息
public void save(User user);
//更新用户信息
public void update(User user);
//删除用户信息
public void delete(int id);
//查询用户信息
public User query(int id);
}
package com.skymr.sphi.service.impl;
import com.skymr.sphi.dao.UserDao;
import com.skymr.sphi.model.User;
import com.skymr.sphi.service.UserService;
public class UserServiceBean implements UserService{
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void delete(int id) {
userDao.delete(id);
}
public User query(int id) {
return userDao.query(id);
}
public void save(User user) {
userDao.save(user);
}
public void update(User user) {
userDao.update(user);
}
}
3.配置文件
1)spring主配置文件 config/applicationContext.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!-- 导入hibernate配置,将原hibernate的一些配置放到spring中管理 -->
<import resource="classpath*:config/spring_annotation-hibernate.xml"/>
<bean id="userDao" class="com.skymr.sphi.dao.UserDao">
<!-- 不知道为什么 不能注解注入,会报错 -->
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="userService" class="com.skymr.sphi.service.impl.UserServiceBean">
<!-- 不知道为什么 不能注解注入,会报错 -->
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
知道使用注解注入失败的原因了,是因为没开启注解的原因.
开启注解
<context:annotation-config></context:annotation-config>
要使用context标签就必须引入规范
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!-- 数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<!-- 这个属性driverClassName为什么在DriverManagerDataSource及父类中找不到呢 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/website"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<!-- sessionFactory配置 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<!-- 设置Hibernate方言 -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<!-- 是否打印sql -->
<prop key="hibernate.show_sql">true</prop>
<!-- 格式化sql -->
<prop key="hibernate.format_sql">true</prop>
<!-- 是否自动更新表 -->
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<!-- 最大抓取深度,如果为0,则关闭默认的外连接抓取。建议值为0-3 -->
<prop key="hibernate.max_fetch_depth">1</prop>
<!-- 用于生成有助于调试的注释信息,默认为关闭 -->
<prop key="hibernate.use_sql_comments">true</prop>
</props>
</property>
<property name="configLocations">
<list>
<value>classpath*:config/hibernate/hibernate.cfg.xml</value>
</list>
</property>
</bean>
</beans>
3)Hibernate自己的配置config/hibernate/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>
<!-- 原来的数据源,用户名,密码等配置都放到了spring中配置了,这里只需要配置映射 -->
<!-- pojo映射配置,以前是一个配置文件***.hbm.xml,现在使用注解方法配置映射了 -->
<mapping class="com.skymr.sphi.model.User"/>
</session-factory>
</hibernate-configuration>
4.实体类及Hibernate注解映射
package com.skymr.sphi.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="test_user") //表名
public class User {
@Id //指定主键
@GeneratedValue
private int id;
@Column(length=32)
private String userName;
@Column(length=32)
private String password;
@Column(length=10)
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
GeneratedValue:指定Id生成策略,默认是auto,就是@GeneratedValue(strategy = GenerationType.AUTO)
5.junit测试
package com.skymr.sphi.test;
import java.sql.SQLException;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.skymr.sphi.model.User;
import com.skymr.sphi.service.UserService;
public class TestMain {
@Test
public void saveUserTest() throws SQLException{
ApplicationContext context= new ClassPathXmlApplicationContext("/config/applicationContext.xml");
UserService service =(UserService) context.getBean("userService");
User user = new User();
user.setUserName("111");
user.setPassword("222");
user.setAge(10);
service.save(user);
}
}
经过测试,数据库中添加了test_user表,并成功添加一行数据.
6.spring管理Hibernate事务
上面例子中的UserDao类中使用的事务是直接写代码的方式,在session操作的前后进行事务的开始与结束,这里可以使用spring来管理事务了.
在spring_annotation-hibernate.xml配置中加入这段:
<!-- spring管理hibernate事务 aop拦截,代理事务 -->
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<!-- 事务特性 ,使用时加载,抽象类 -->
<bean id="transactionBean"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
lazy-init="true"
abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="update*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="delete*">PROPAGATION_NEVER</prop>
<prop key="get*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>
transactionAttributes的各种属性的意义如下:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
readonly 就是read only, 设置操作权限为只读,一般用于查询的方法,优化作用.
经过以上配置后,spring就拦截了hibernate的数据库操作,对操作进行事务管理.
修改UserDao类,去掉代的事务代码
package com.skymr.sphi.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.skymr.sphi.model.User;
public class UserDao {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void save(User user){
System.out.println("执行UserDao save方法:");
Session session = sessionFactory.openSession();
session.save(user);
session.close();
}
public void update(User user){
System.out.println("执行UserDao update方法:");
Session session = sessionFactory.openSession();
session.update(user);
session.close();
}
public void delete(int id){
System.out.println("执行UserDao delete方法:");
Session session = sessionFactory.openSession();
session.delete(id);
session.close();
}
public User query(int id){
System.out.println("执行UserDao query方法:");
Session session = sessionFactory.openSession();
User ret = (User)session.get(User.class, id);
session.close();
return ret;
}
}
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in URL [file:/E:/webworkspace/spring_hibernate/WebRoot/WEB-INF/classes/config/spring_annotation-hibernate.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getConnectionProvider()Lorg/hibernate/service/jdbc/connections/spi/ConnectionProvider;
都是照着视频做的,没理由出错啊.
上网查找,发现是spring与hibernate版本不匹配的原因:
原因,在使用Spring3.2.x与Hibernate4.3.x(4.1.7以上)的版本整合时出的错。 解决方案:把Hibernate降至4.1.7或以下的版本就行了。 |
于是下载hibernate 4.1.10,测试后正常.
7.UserDao调整
Dao层的Bean(UserDao)是个类,没有接口,是不规范的,spring中都要使用接口的,因为spring的底层的代理拦截(AOP原理)必须要有接口,我记得有另一种方法(动态代理)是不用代理的,既然spring这样要求,那就再加入个接口吧
package com.skymr.sphi.dao;
import com.skymr.sphi.model.User;
public interface UserDao {
public void save(User user);
public void update(User user);
public void delete(int id);
public User query(int id);
}
package com.skymr.sphi.dao.impl;
import javax.annotation.Resource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import com.skymr.sphi.dao.UserDao;
import com.skymr.sphi.model.User;
public class UserDaoBean implements UserDao{
@Resource
private SessionFactory sessionFactory;
public void save(User user){
System.out.println("执行UserDao save方法:");
Session session = sessionFactory.openSession();
session.save(user);
session.close();
}
public void update(User user){
System.out.println("执行UserDao update方法:");
Session session = sessionFactory.openSession();
session.update(user);
session.close();
}
public void delete(int id){
System.out.println("执行UserDao delete方法:");
Session session = sessionFactory.openSession();
session.delete(id);
session.close();
}
public User query(int id){
System.out.println("执行UserDao query方法:");
Session session = sessionFactory.openSession();
User ret = (User)session.get(User.class, id);
session.close();
return ret;
}
}