博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
三种数据库访问——Spring3.2 + Hibernate4.2
阅读量:5076 次
发布时间:2019-06-12

本文共 9108 字,大约阅读时间需要 30 分钟。

前三篇随笔中介绍了 、、。

本文继续介绍第三种数据库访问的解决方案: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工程,工程结构、依赖的配置如下:

junit
junit
4.11
mysql
mysql-connector-java
5.1.26
com.alibaba
druid
0.2.25
org.springframework
spring-context
3.2.4.RELEASE
org.springframework
spring-orm
3.2.4.RELEASE
org.hibernate
hibernate-core
4.2.4.Final

依赖的项目有:Junit;mysql驱动;druid:一款高效的数据库连接池,下面会看到如何应用它;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

在这,我应用了阿里巴巴开发的一个高效的数据库连接池:druid。

阿里巴巴官网上介绍,druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

与druid相关的详细内容可以看我之前的一篇随笔。

 

4、配置SessonFactory、配置事务处理器、配置bean的依赖关系

applicationContext-hibernate.xml

org.hibernate.dialect.MySQLDialect
true
false
false
false

在这里用的是基于注解的事务配置方式。用注解的好处,是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 
{ private Class
entityClass; private SessionFactory sessionFactory; protected AbstractHibernateDao(Class
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
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
query(String sql,Object[] args);}public class UserDaoImpl extends AbstractHibernateDao
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;@Transactionalpublic 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
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事务的介绍,情况上一篇随笔:

 

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();    }}

测试结果,在这里就不说了。

 

 

参考:

转载于:https://www.cnblogs.com/windlaughing/p/3289552.html

你可能感兴趣的文章
一步步学习微软InfoPath2010和SP2010--第七章节--从SP列表和业务数据连接接收数据(4)--外部项目选取器和业务数据连接...
查看>>
oracle 报错ORA-12514: TNS:listener does not currently know of service requested in connec
查看>>
基于grunt构建的前端集成开发环境
查看>>
利用循环播放dataurl的视频来防止锁屏:NoSleep.js
查看>>
python3 生成器与迭代器
查看>>
java编写提升性能的代码
查看>>
Abstract Factory Pattern
查看>>
list 容器 排序函数.xml
查看>>
《Genesis-3D开源游戏引擎完整实例教程-跑酷游戏篇03:暂停游戏》
查看>>
CPU,寄存器,一缓二缓.... RAM ROM 外部存储器等简介
查看>>
windows下编译FreeSwitch
查看>>
git .gitignore 文件不起作用
查看>>
Alan Turing的纪录片观后感
查看>>
c#自定义控件中的事件处理
查看>>
django Models 常用的字段和参数
查看>>
IOS--沙盒机制
查看>>
使用 JointCode.Shuttle 访问任意 AppDomain 的服务
查看>>
sqlite的坑
查看>>
digitalocean --- How To Install Apache Tomcat 8 on Ubuntu 16.04
查看>>
【题解】[P4178 Tree]
查看>>