三种数据库访问——Spring JDBC
本篇随笔是上两篇的延续:三种数据库访问——原生JDBC;数据库连接池:Druid
Spring的JDBC框架
Spring主要提供JDBC模板方式、关系数据库对象化方式、SimpleJdbc方式、事务管理来简化JDBC编程
Spring提供了3个模板类:
- JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。
- NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数。
- SimpleJdbcTemplate:利用Java 5的特性,比如自动装箱、通用(generic)和可变参数列表来简化JDBC模板的使用。
JdbcTemplate主要提供以下4类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
示例项目
接下来,通过一个示例项目来展示如何使用Spring的JDBC框架访问数据库。假设该项目的功能有:保存用户信息、查询用户信息。
1、首先创建数据库及用户表:
CREATE TABLE `user` (
`id` int(10) NOT NULL auto_increment,
`name` varchar(30) default NULL,
`age` int(3) default NULL,
PRIMARY KEY (`id`)
)
2、创建工程(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-jdbc</artifactId>
<version>3.2.4.RELEASE</version>
</dependency>
依赖的包有:Junit、mysql驱动器、druid(阿里巴巴开发的高性能的数据库连接池)、spring-context、spring-jdbc
3、实体类User
public class User implements Serializable{
private Long id;
private String name;
private Integer age; //setter getter 略 public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
4、Dao接口及实现
package edu.shao.springJdbc.dao; import java.util.List;
import edu.shao.springJdbc.po.User; public interface IUserDao {
public void save(User user);
public List<User> query(String sql,Object[] args);
}
package edu.shao.springJdbc.dao.impl; import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import edu.shao.springJdbc.dao.IUserDao;
import edu.shao.springJdbc.po.User; public class UserDaoImpl extends JdbcDaoSupport implements IUserDao { class UserRowMapper implements RowMapper<User> {
//实现ResultSet到User实体的转换
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User m = new User();
m.setId(rs.getLong("id"));
m.setName(rs.getString("name"));
m.setAge(rs.getInt("age"));
return m;
}
}; public void save(User model) {
getJdbcTemplate().update("insert into user(name,age) values(?,?)",
model.getName(), model.getAge());
} public List<User> query(String sql, Object[] args) {
return getJdbcTemplate().query(sql, args, new UserRowMapper());
}
}
5、Service接口及实现:
package edu.shao.springJdbc.service; public interface IUserService {
void saveUser();
void saveUserThrowException() throws Exception;
void findUsers();
}
package edu.shao.springJdbc.service.impl; import java.util.List;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import edu.shao.springJdbc.dao.IUserDao;
import edu.shao.springJdbc.po.User;
import edu.shao.springJdbc.service.IUserService; @Transactional
public class UserServiceImpl implements IUserService {
private IUserDao userDao; public void saveUser() {
User u1=new User();
u1.setName("邵");
u1.setAge(24);
userDao.save(u1); if(1+1>1){
throw new RuntimeException("Runtime error...");//抛出运行时异常:RuntimeException
} User u2=new User();
u2.setName("陈");
u2.setAge(20);
userDao.save(u2);
} 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.NOT_SUPPORTED,readOnly=true)
public void findUsers() {
List<User> users=userDao.query("select * from user where age>?", new Object[]{17});
for (User user : users) {
System.out.println(user);
} } //setter getter略
}
Spring对事务的管理有丰富的支持,Spring提供了编程式配置事务和声明式配置事务,其中,声明式事务有以下两种方式 :
- 一种是使用Annotation注解的方式(官方推荐)
- 一种是基于Xml的方式
(编程式的事务处理有些侵入性。通常我们的事务需求并没有要求在事务的边界上进行如此精确的控制,我们一般采用"声明式事务"。)
上面我们采用了基于注解的方式来配置事务。
6、配置数据库连接池、配置bean的依赖关系、配置事务处理器
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>
applicationContext-jdbc.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="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean> <!-- 首先定义抽象的abstractDao,其有一个jdbcTemplate属性,从而可以让继承的子类自动继承jdbcTemplate属性注入; -->
<bean id="abstractDao" abstract="true">
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean> <bean id="userDao" class="edu.shao.springJdbc.dao.impl.UserDaoImpl"
parent="abstractDao" /> <bean id="userService" class="edu.shao.springJdbc.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean> <bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean> <tx:annotation-driven transaction-manager="txManager" />
</beans>
上面<tx:annotation-driven transaction-manager="txManager" /> 这句话的作用是注册事务处理器。
我们只需要在类上加上注解@Transactional,就可以指定这个类需要受Spring的事务管理。默认Spring为每个方法开启一个事务,如果方法发生运行期异常(RuntimeException),事务会进行回滚;如果发生一般的异常(Exception),事务不进行回滚。
7、测试
package edu.shao.springJdbc; import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.shao.springJdbc.service.IUserService; public class SpringJdbcTest {
private static ApplicationContext ctx = null; @BeforeClass //表示在所以测试方法之前执行,且只执行一次。
public static void onlyOnce() {
ctx = new ClassPathXmlApplicationContext("db/applicationContext-jdbc.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();
}
}
运行测试类,
第一个测试方法,后台输出异常:java.lang.RuntimeException,查看数据库发现数据没有插入,说明事务进行了回滚。
第二个测试方法,后台输出异常:java.lang.Exception ,查看数据库发现第一条数据插入,而第二条数据没有插入,说明事务没有进行了回滚。
说明了Spring的事务支持默认只对运行期异常(RuntimeException)进行回滚,如果执行sql操作的时候会发生sql异常,不属于运行期异常,那Spring是怎么进行事务回滚的呢 ?
Spring把SQLException等异常转化为了DataAccessException,后者是一种RuntimeException,所以只对RuntimeException异常进行回滚是很合理的。
其他注解方式:
- 修改Spring的默认配置,当发生RuntimeException时,可以不让它进行事务回滚 ,只需要加上一个@Transactional(noRollbackFor=RuntimeException.class)
- 配置对Exception进行回滚,在方法上添加@Transactional(rollbackFor=Exception.class)
- 对于一些查询工作,因为不需要配置事务支持,我们给其添加注解: @Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)。readOnly=true表示事务中不允许存在更新操作.
关于事务的传播属性有下面几种配置:
- REQUIRED:业务方法需要在一个事务中运行,如果方法运行时,已经处于一个事务中,那么加入到该事务中。否则自己创建一个新的事务。(Spring默认的事务传播属性)
- NOT_SUPPORTED:声明方法不需要事务,如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务被挂起,在方法调用结束后,原先的事务便会恢复执行
- REQUIRESNEW:不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法运行时已经存在一个事务,则该事务会被挂起,新的事务被创建,直到方法执行结束,新事务才结束,原先的事务才恢复执行.
- MANDATORY:指定业务方法只能在一个已经存在的事务中执行,业务方法不能自己发起事务,如果业务方法没有在事务的环境下调用,则容器会抛出异常
- SUPPORTS:如果业务方法在事务中被调用,则成为事务中的一部分,如果没有在事务中调用,则在没有事务的环境下执行
- NEVER:指定业务方法绝对不能在事务范围内运行,否则会抛出异常.
- NESTED:如果业务方法运行时已经存在一个事务,则新建一个嵌套的事务,该事务可以有多个回滚点,如果没有事务,则按REQUIRED属性执行。 注意:业务方法内部事务的回滚不会对外部事务造成影响,但是外部事务的回滚会影响内部事务
总结:
事务是企业应用开发的重要组成部分,它使软件更加可靠。它们确保一种要么全有 要么全无的行为,防止数据不一致而导致的不可预测的错误发生。 事务同时也支持并发,防止并发应用线程在操作同一数据时互相影响。
以前我们写Jdbc代码的时候,可能需要自己手动去开启事务,然后方法执行结束之后再去提交事务,全部都嵌套在我们的业务代码之中,具有很强的侵入性....
使用Spring提供事务管理机制,我们只需要配置XML或使用Annotion进行注解就可以实现事务的管理和配置,减少了代码之间的耦合,配置也很方便,很大程度上提升了我们的开发效率。
参考:http://www.iteye.com/topic/480432
三种数据库访问——Spring JDBC的更多相关文章
- 三种数据库访问——原生JDBC
原生的JDBC编程主要分一下几个步骤: (原生的JDBC编程指,仅应用java.sql包下的接口和数据库驱动类编程,而不借助任何框架) 1. 加载JDBC驱动程序: 2. 负责管理JDBC驱动程序的类 ...
- 三种数据库访问——Spring3.2 + Hibernate4.2
前三篇随笔中介绍了 用原生的JDBC访问数据库.一种高效的数据库连接池druid.用Spring的JDBC框架访问数据库. 本文继续介绍第三种数据库访问的解决方案:Spring3.2 + Hibern ...
- qlserver、Mysql、Oracle三种数据库的优缺点总结
这篇文章主要介绍了sqlserver.Mysql.Oracle三种数据库的优缺点总结,需要的朋友可以参考下 一.sqlserver优点:易用性.适合分布式组织的可伸缩性.用于决策支持的数据仓库功能 ...
- MySQL - 常见的三种数据库存储引擎
原文:MySQL - 常见的三种数据库存储引擎 数据库存储引擎:是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据.不同的存储引擎提供不同的存储机制.索引技巧. ...
- MySQL、SqlServer、Oracle 三种数据库的优缺点
MySQL.SqlServer.Oracle 三种数据库的优缺点 一.MySQL 优点: 缺点: 二.SqlServer 优点: 缺点: 三.Oracle 优点: 缺点: 一.MySQL 优点: 体积 ...
- MySQL、SqlServer、Oracle,这三种数据库的优缺点,你知道吗?
盘点MySQL.SqlServer.Oracle 三种数据库优缺点 MySQL SqlServer Oracle 一.MySQL 优 点 体积小.速度快.总体拥有成本低,开源:支持多种操作系统:是开源 ...
- 浅淡Webservice、WSDL三种服务访问的方式(附案例)
Webservice Webservice是使应用程序以与平台和编程语言无关的方式进行相互通信技术. eg:站点提供访问的数据接口:新浪微博.淘宝. 官方解释:它是一种构建应用程序的普遍模型,可以在任 ...
- MySQL、SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法
在这里主要讲解一下MySQL.SQLServer2000(及SQLServer2005)和ORCALE三种数据库实现分页查询的方法. 可能会有人说这些网上都有,但我的主要目的是把这些知识通过我实际的应 ...
- Kubernetes的三种外部访问方式:NodePort、LoadBalancer和Ingress(转发)
原文 http://cloud.51cto.com/art/201804/570386.htm Kubernetes的三种外部访问方式:NodePort.LoadBalancer和Ingress 最近 ...
随机推荐
- 设计模式总结(《Head First设计模式》学习总结)
写在前面: 学习过程中不仅要熟练掌握技能,理论的消化吸收也必不可少.虽然个人更倾向于学习技术类的东西(短时间的精力投入很快就能看到成效...),但看了很多前辈的经验总结后才知道理论性的东西是绝对不能忽 ...
- 找不到请求的 .Net Framework Data Provider
1.安装 mysql-connector-net-6.9.10.msi 2.修改C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\machine ...
- C# 实现邮件代发
由于自己很好奇,有一些推广之类的 邮件,发件人后面,都有一个 由 .... 代发. 所以,查找了一些资料,来验证了一下实现方法. 咱们先来看看,实现代发的 理想效果图 当然,这一种,是利用 代发的 邮 ...
- 文件操作(FILE)与常用文件操作函数
文件 1.文件基本概念 C程序把文件分为ASCII文件和二进制文件,ASCII文件又称文本文件,二进制文件和文本文件(也称ASCII码文件)二进制文件中,数值型数据是以二进制形式存储的, 而在文本文件 ...
- ESP8266 wifi干扰、钓鱼实现
说明:绝大部分都是对着下面的参考文章来做的.这里只把基本流程和我自己遇到的问题写一下.如有其他问题可以访问文章末的参考文章进行查找! esp8266模块 我们需要购买一块esp8266模块,如下图所示 ...
- 用xshell ssh连接测试服务器时候出的问题
问题还原:用ssh连接测试服务器 给我结结实实报了个错 FBIwarning: ------------------------------------------------------------ ...
- Advanced Debugging and the Address Sanitizer
A debug trick 在异常端点处运行 po $arg1,找出异常信息.  Address Sanitizer 概述 是一个运行时检测工具 发现内存问题 可以用于模拟器和设备 可以发现的问题 ...
- 【qboi冲刺NOIP2017复赛试题4】 全套题目+题解+程序
作为一个好人(验题人),我给大家奉上下这套题的题解,并且预祝大家这套题能够AK: T1题面:Alice现在有n根木棍,他们长度为1,2,3....n,Bob想把某一些木棍去掉,使得Alice剩下的木棍 ...
- SQL实现数据行列转换
前言: 在日常的工作中,使用数据库查看数据是很经常的事,数据库的数据非常多,如果此时的数据设计是一行行的设计话,就会有多行同一个用户的数据,查看起来比较费劲,如果数据较多时,不方便查看,为了更加方便工 ...
- oracle 转 mysql 最新有效法
关键字:Oracle 转 MySQL . Oracle TO MySQL 没事试用了一下Navicat家族的新产品Navicat Premium,他集 Oracle.MySQL和PostgreSQL管 ...