Spring3.2 + Hibernate4.2
Spring3.2 + Hibernate4.2
前三篇随笔中介绍了 用原生的JDBC访问数据库、一种高效的数据库连接池druid、用Spring的JDBC框架访问数据库。
本文继续介绍第三种数据库访问的解决方案:Spring3.2 + Hibernate4.2
ORM框架
Hibernate是一个开源的ORM框架,能自动为对象生成相应SQL并透明的持久化对象到数据库,我们首先来了解一下什么是“ORM”。
ORM全称对象关系映射(Object/Relation Mapping),指将Java对象状态自动映射到关系数据库中的数据上,从而提供透明化的持久化支持,即把一种形式转化为另一种形式。
对象与关系数据库之间是不匹配,我们把这种不匹配称为阻抗失配,主要表现在:
1. 关系数据库首先不支持面向对象技术,如继承、多态;
2. 关系数据库是由表来存放数据,而面向对象使用对象来存放状态;
3. 如何将对象透明的持久化到关系数据库表中;
4. 如果一个对象存在横跨多个表的数据,应该如何为对象建模和映射。
其中这些阻抗失配只是其中的一小部分,比如还有如何将SQL集合函数结果集映射到对象,如何在对象中处理主键等。ORM框架就是用来解决这种阻抗失配,提供关系数据库的对象化支持。
目前已经有许多ORM框架产生,如Hibernate、JDO、JPA、iBATIS等等,这些ORM框架各有特色,Spring对这些ORM框架提供了很好的支持。
示例项目
接下来,我们还是通过一个实际的项目实践Spring+Hibernate框架访问数据库。假设该项目的功能有:保存用户信息、查询用户信息。
1、工程结构和依赖项
这是一个Maven工程,工程结构、依赖的配置如下:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.25</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.4.Final</version>
</dependency>
依赖的项目有:Junit;mysql驱动;druld:一款高效的数据库连接池,下面会看到如何应用它;spring-context;spring-orm;hibernate-core
2、数据库表及实体类
CREATE TABLE `user` (
`id` int(10) NOT NULL auto_increment,
`name` varchar(30) default NULL,
`age` int(3) default NULL,
PRIMARY KEY (`id`)
)
import java.io.Serializable; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table; @Entity
@Table(name="user")
public class User implements Serializable{
private static final long serialVersionUID = 1724315528421427938L; @Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;
@Column(name="name",nullable=true,length=25)
private String name;
@Column(name="age",nullable=true)
private Integer age; //setter getter 略 @Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
这个Pojo类和上面的数据库表对应,我们采用JPA注解来配置这种对应关系。(JPA是一种规范,通过JDK 5.0注解或XML描述对象-关系表的映射关系)。
3、配置数据库连接池
applicationContext-dataSource.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="initialSize" value="1" />
<property name="maxActive" value="20" />
</bean> </beans>
在这,我应用了阿里巴巴开发的一个高效的数据库连接池:druid。
阿里巴巴官网上介绍,druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
与druid相关的详细内容可以看我之前的一篇随笔。
4、配置SessonFactory、配置事务处理器、配置bean的依赖关系
applicationContext-hibernate.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <import resource="applicationContext-dataSource.xml" /> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="edu.shao.springHibernate.po" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean> <bean id="userService" class="edu.shao.springHibernate.service.impl.UserService">
<property name="userDao">
<bean class="edu.shao.springHibernate.dao.impl.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</property>
</bean> <!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean> <tx:annotation-driven transaction-manager="transactionManager"/> </beans>
在这里用的是基于注解的事务配置方式。用注解的好处,是Service中的方法命名不需要特别规定(基于xml的事务配置方式需要Service的方法命名按照某一自定义规范命名),只需要在Service类上或方法上加上@Transactional注解即可;缺点是没有做到集中声明,如果在某个Service层的接口忘记声明事务,那么事务就无法生效。
<tx:annotation-driven transaction-manager="txManager" /> 这句话的作用是注册事务注解处理器。
如果方法发生运行期异常(RuntimeException),事务会进行回滚;如果发生一般的异常(Exception),事务不进行回滚。
<property name="packagesToScan" value="edu.shao.springHibernate.po" /> 让Hibernate自动扫描指定的包下面注解的实体类,也就是User类。
5、Dao接口及实现
AbstractHibernateDao是一个抽象的Dao的父类,实现了一般的保存、删除、查询等方法。 具体的Dao类可以继承该类,并实现对某一实体特殊的访问方法。
AbstractHibernateDao类中注入了SessionFactory ,通过方法“sessionFactory.getCurrentSession();”来获得一个session,用此session保存、更新、删除、查找实体。
这里因为session.get()方法,都需要传入一个Class类型的参数,所以定义了entityClass字段,在具体Dao的构造方法中传入,下面会看到。
import java.io.Serializable;
import java.util.List; import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory; public abstract class AbstractHibernateDao <E extends Serializable>{
private Class<E> entityClass;
private SessionFactory sessionFactory; protected AbstractHibernateDao(Class<E> entityClass) {
this.entityClass = entityClass;
} public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
} public E findById(Serializable id) {
return (E) getCurrentSession().get(entityClass, id);
} public void save(E e) {
getCurrentSession().save(e);
} public void delete(E e) {
getCurrentSession().delete(e);
} public List<E> query(String hql, Object[] args) {
Query query=getCurrentSession().createQuery(hql);
if(args!=null){
for (int i = 0; i < args.length; i++) {
query.setParameter(i, args[i]);
}
}
return query.list();
} //setter getter
}
下面是具体的Dao的接口和实现。
UserDaoImpl在构造参数中传入了User.class,用于初始化AbstractHibernateDao里的entityClass字段 。
public interface IUserDao {
public void save(User user);
public List<User> query(String sql,Object[] args);
} public class UserDaoImpl extends AbstractHibernateDao<User> implements IUserDao { public UserDaoImpl() {
super(User.class);
} }
6、Service接口及实现
public interface IUserService {
void saveUser();
void saveUserThrowException() throws Exception;
void findUsers();
}
import java.util.List; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import edu.shao.springHibernate.dao.IUserDao;
import edu.shao.springHibernate.po.User;
import edu.shao.springHibernate.service.IUserService; @Transactional
public class UserService implements IUserService{
private IUserDao userDao; public void saveUser() {
User u1=new User();
u1.setName("邵");
u1.setAge(24);
userDao.save(u1); //测试时,可以添加此异常,或去掉异常,测试Spring对事物的管理
// if(1+1>1){
// throw new RuntimeException("Runtime error...");//抛出运行时异常:RuntimeException
// } User u2=new User();
u2.setName("陈");
u2.setAge(20);
userDao.save(u2);
} @Transactional(rollbackFor={Exception.class})
public void saveUserThrowException() throws Exception {
User u1=new User();
u1.setName("邵");
u1.setAge(24);
userDao.save(u1); if(1+1>1){
throw new Exception("Runtime error...");//抛出一般的异常:Exception
} User u2=new User();
u2.setName("陈");
u2.setAge(20);
userDao.save(u2); } @Transactional(propagation=Propagation.REQUIRED,readOnly=true)
public void findUsers() {
List<User> users=userDao.query("from User where name=?", new Object[]{"邵"});
for (User user : users) {
System.out.println(user);
}
} public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
如果没有事务,执行代码“sessionFactory.getCurrentSession(); ”,会抛出No Session found for current thread。
getCurrentSession() 只有在一个事务之内才有意义,所以hibernate4要求最小事务级别必须是Required,如果是以下的级别,或者没有开启事务的话,无法得到当前的Session。
上面代码中,propagation参数,至少要到REQUIRED,否则会抛出异常:No Session found for current thread
对于运行时,这个可能不是很大的问题,因为在Service层一般都会开启事务,只要保证级别高于Required就可以了。
更多关于Spring事务的介绍,情况上一篇随笔:三种数据库访问——Spring JDBC
7、测试
package edu.shao.springHibernate; import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.shao.springHibernate.service.IUserService; public class SpringHibernateTest {
private static ApplicationContext ctx = null; @BeforeClass
public static void onlyOnce() {
ctx = new ClassPathXmlApplicationContext("db/applicationContext-hibernate.xml");
} @Test
public void testSave(){
IUserService service=ctx.getBean("userService",IUserService.class);
service.saveUser();
} // @Test
public void testSaveThrowException() throws Exception{
IUserService service=ctx.getBean("userService",IUserService.class);
service.saveUserThrowException();
} // @Test
public void testJDBCDaoQuery(){
IUserService service=ctx.getBean("userService",IUserService.class);
service.findUsers();
}
}
测试结果,在这里就不说了。
Spring3.2 + Hibernate4.2的更多相关文章
- Spring3+SpingMVC+Hibernate4全注解环境配置
Spring3+SpingMVC+Hibernate4全注解环境配置 我没有使用maven,直接使用Eclipse创建动态Web项目,jar包复制在了lib下.这样做导致我马上概述的项目既依赖Ecli ...
- 三种数据库访问——Spring3.2 + Hibernate4.2
前三篇随笔中介绍了 用原生的JDBC访问数据库.一种高效的数据库连接池druid.用Spring的JDBC框架访问数据库. 本文继续介绍第三种数据库访问的解决方案:Spring3.2 + Hibern ...
- struts2.3+spring3.2+hibernate4.2例子
有些教程比较老,可是版本更新不等人,基于马士兵老师小例子,自己重新引用了新的包,调试确实有点烦人,但是通过英文文档和google解决问题.官网的更新超快,struts2.3+spring3.2+hib ...
- struts2 spring3.2 hibernate4.1 框架搭建 整合
ssh是企业开发中常遇到的框架组合,现将框架的搭建过程记录下来,以便以后查看.我的搭建过程是,首先struts,然后spring,最后hibernate.struts2的最新版本为2.3.8,我下载的 ...
- SSH的简单入门体验(Struts2.1+Spring3.1+Hibernate4.1)- 查询系统(上)
所谓SSH,指的是struts+spring+hibernate的一个集成框架,它是目前较流行的一种Web应用程序的开源框架. 集成SSH框架的系统从职责上分为四层:表示层.业务逻辑层.数据持久层和域 ...
- Struts2.3+Spring3.2+Hibernate4.2框架搭建
一.环境 SSH使用的版本:struts2.3.14.spring3.2.2.hibernate4.2.0 数据库:MYSQL tomcat版本:apache-tomcat-7.0.42 二.所需要导 ...
- Spring3 整合 Hibernate4实现数据库操作(1)
Hibernate知识学习:http://justsee.iteye.com/blog/1061576 注意Hibernate4在开发当中的一些改变 :http://snake-hand.iteye ...
- struts2+Hibernate4+spring3+EasyUI环境搭建之四:引入hibernate4以及spring3与hibernate4整合
1.导入hibernate4 jar包:注意之前引入的struts2需要排除javassist 否则冲突 <!-- hibernate4 --> <dependency> & ...
- Spring3+Struts2+Hibernate4+Mybatis整合的一个maven例子
说明: 1.用了maven去搞这个demo,懒得去导jar包... 2.这个demo用了spring去做Ioc,事务的aop:用了struts2去做“MVC”(没有用到任何UI技术,有点对不起这个MV ...
随机推荐
- c/c++ 基金会(七) 功能覆盖,虚函数,纯虚函数控制
1.功能覆盖 ClassA , ClassB ,其中ClassB继承ClassA 类的定义如下面的: #ifndef _CLASSA_H #define _CLASSA_H #include < ...
- 搭建一个BS 的简单SOA 架构(直接通过jquery 调用后台的 wcf 服务的架构)(第一天)
亲们!还在用传统的三层架构吗?你还在对SOA架构 不了解吗? 那就赶快来学习下一个 比较简单的SOA的架构吧!我会手把手的 教会你们怎么搭建这个 简单的SOA的架构. 其中用的技术点保证 WCF,a ...
- CSS3火焰文字特效制作教程
原文:CSS3火焰文字特效制作教程 用一句很俗气的话概括这两天的情况就是:“最近很忙”,虽然手头上有不少很酷的HTML5和CSS3资源,但确实没时间将它们的实现过程写成教程分享给大家.今天刚完成了一个 ...
- [Android]Parcelable encountered IOException writing serializable object (name = xxx)
Activity之间通过Intent传递值,支持基本数据类型和String对象及它们的数组对象byte.byte[].char.char[].boolean.boolean[].short.short ...
- Objective-C系列
我的Objective-C系列文章和坚持写博客的感想 做iOS开发有一段时间了,也有自己上线的App产品,也在坚持着发表技术博客总结自己所学的东西.在写博客的时候虽然博文中不免有错别字,但每句话都 ...
- HDU 1983 BFS&&DFS
大多数刚需封锁4区域可以,DFS地区封锁.BFS无论是通过 #include "stdio.h" #include "string.h" #include &q ...
- RegularExpressionValidator控件
原文:RegularExpressionValidator控件 ★搜Asp.net★(www.soAsp.net),为专业技术文档网站.包括Asp.net开发技术文档·C#开发技术文档·Access/ ...
- C#中调用Outlook API 发起会议
原文:C#中调用Outlook API 发起会议 在我上一篇博文中曾提到了 SharePoint 中调用传出电子邮件中的邮件服务器及地址发送邮件 但是,里面的方法只能用于发送普通电子邮件.如果要发起会 ...
- javascript实现代码高亮
javascript实现代码高亮-wangHighLighter.js 1. 引言 (先贴出wangHighLighter.js的github地址:https://github.com/wangfup ...
- leetcode第12题--Integer to Roman
Problem: Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range ...