Spring中使用JDBC
Spring中的数据库异常体系
使用JDBC(不使用Spring)的时候,我们需要强制捕获SQLException,否则无法使用JDBC处理任何事情。SQLException表示尝试访问数据库的时候出现问题,但是这个异常却没有告诉我们哪里出错以及如何处理。可能出现SQLException的情况有:
- 应用程序无法连接数据库
- 查询的SQL有问题
- 查询中的表,列不存在
- 尝试插入或更新的数据违法数据库的约束
还有其他的数据库有关的异常,但是真正抛出SQLException的时候,我们没有办法准确的定位,只有靠经验与猜测去处理。而且抛出SQLException意味着出现致命性的错误,程序也没有办法继续处理。
一些持久层框架都有相对丰富的异常体系,例如Hibernate有二十几左右的异常,分别对应特定的数据访问问题。这样就可以针对特定的异常编写catch代码块。但是,这种Hibernate的异常是与对应的框架相对应的,我们如果希望特定的持久框架独立于数据访问层。如果我们将这些Hibernate的异常抛出去,那么我们对Hibernate的使用将渗透到其他层。如果不这样做,就需要将这些特定的异常捕获然后将其转换为与平台无关的异常再次处理。
一方面,JDBC的异常过于简单,而Hibernate的异常体系又是与其平台有关的。Spring 针对这个问题提供了多个数据访问异常,Spring的异常体系并没有与特定持久方法相关联,这样我们就不用关心所选择的持久化方案。这有助于我们将所选择的具体持久化技术与数据访问层隔离开。而且Spring的数据访问异常都继承于DataAccessException,这是一个非检查异常,也就是说没有必要捕获Spriing这些数据访问异常(如果想捕获也是完全可以的)。
第一步 配置数据源
Spring的模板类处理数据访问层的国定部分——事务控制,管理控制以及处理异常。同时,应用程序相关的数据访问——语句,绑定参数以及真理数据集需要我们自己处理。针对不同的持久化平台,Spring提供了可选的模板,如果使用JDBC就选择JdbcTemplate,如果使用对象关系映射框架,那么可以使用HibernateTemplcate或JpaTemplcate。
但首先要说明的是Spring所支持的持久功能都需要依赖数据源。所以不要忘记配置数据源,并将其作为第一步(建议使用数据库连接池或者JNDI的方式,如果有可能使用Spring的profile也是极好的)。
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setUrl("jdbc:mysql:///crud");
dataSource.setUsername("root");
dataSource.setPassword("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
return dataSource;
}
第二步 在Spring中使用JDBC
JDBC是建立在SQL之上的,而SQL本身就是数据库访问语言,此外,与其他的技术相比,直接使用JDBC可以更好对数据库进行调优,JDBC允许使用数据库的所有特性,而这是其他框架不鼓励甚至是禁止的。相对于其他的持久层框架,JDBC能够让我们在更底层上处理数据,我们完全可以控制应用程序如何读取和管理数据,这是一种细粒度的数据访问方式。
使用JDBC模板
Spring的JDBC模板承担了资源管理和异常处理的工作,从而简化了JDBC代码,将数据访问的样板代码抽象到模板类中,Spring为JDBC提供了三个JDBC模版类:
- JdbcTemplate:最基本的Spring JDBC模板类,支持基于索引参数(?)的查询。
- NamedParameterJdbcTemplate:使用该模板类执行查询的时候使用命名参数的方式绑定到SQL,而不是用索引参数。
- SimpleJdbcTemplate:Spring3.1之后已弃用
只有我们需要使用命名参数的时候,才使用NamedParameterJdbcTemplate,对于的大多数JDBC任务使用JdbcTemplate就是最好的方案。为了JdbcTemplate可以正常工作,只需要为其配置DataSource:
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
然后,我们就可以将JdbcTemplate装配到Repository中了。
@Repository
public class JdbcRepository { @Autowired
private JdbcOperations jdbcOperations;
这里使用的是 JdbcOperations ,JdbcOperations接口定义了JdbcTemplate模板类所实现的方法,使用接口而不是具体的某一个JDBC模板类,保证松耦合。这里使用Spring的@AutoWired,其实使用@Inject作也可以,只不过后者是Java的注入规范中的注解。
使用模板类之后所有的样板代码隐藏到JDBC模板类中,并且也不用对SQLException进行处理,在内部,JdbcTemplate将会捕获说有可能抛出的SQLException,并将其转换为Spring中通用的数据访问异常,然后将其重新抛出。
使用JdbcTemplate读取数据
JdbcTemplate中有众多query...()的方法用于读取数据,但是对于需要将返回结果封装为对象的操作,需要有一些特殊处理。这个对象需要实现RowMapper接口,对于查询所返回的每一行数据,JdbcTemplate将会调用RowMapper的mapRow方法,并传入一个ResultSet和包含行号的整数。
private static final class SpitterRowMapper implements RowMapper<Spitter> {
public Spitter mapRow(ResultSet rs, int rowNum) throws SQLException {
//这段代码摘自书本
long id = rs.getLong("id");
String username = rs.getString("username");
String password = rs.getString("password");
String fullName = rs.getString("fullname");
String email = rs.getString("email");
boolean updateByEmail = rs.getBoolean("updateByEmail");
return new Spitter(id, username, password, fullName, email, updateByEmail);
}
}
因为RowMapper接口中只有一个mapRow方法,它完全符合函数式接口的标准。这意味着使用Java8来开发应用的化可以使用Lambda表达式,而不必使用具体的实现类了。或者使用Java8的方法引用,在单独的方法中定义映射规则:
public Dept findOne(Integer deptId) {
return jdbcOperations.queryForObject(SELECT_SQL, this::mapDept,deptId);
}
private Dept mapDept(ResultSet rs,int row)throws SQLException {
return new Dept(rs.getInt("dept_id"),rs.getString("dept_name"));
}
但是,不论使用Lambda表达式还是方法引用,都需要保证接受与mapRow相同的参数。
使用命名参数
使用索引参数的时候,需要注意参数的顺序,在将值传递给繁华的是否需要保证正确的顺序。如果在修改SQL时改变了参数的顺序,那我们还需要修改参数值的顺序。而我们使用命名参数,命名参数可以给SQL中的每一个参数一个明确的名字,在绑定值得时候通过名字来引用参数。
private static final String SQL_INSERT_SPITTER="insert into spitter(username,password,fullname)"+"values(:username,:password,:fullname)";
使用命名参数查询,绑定值得顺序就不重要了,如果SQL改变导致参数顺序与之前不一致,我们不需要修改绑定的代码。
NamedParameterJdbcTemplate是一个特殊得JDBC模板类,它使用命名参数。NamedParameterJdbcTemplate得用法与JdbcTemplate一致:
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
然后,就开始在Repository中使用吧:
public void addSpitter(Spitter spitter){
Map<String,Object> map=new HashMap<String,Object>();
map.put("username",spitter.getUsername());
map.put("password",spitter.getPassword());
map.put("username",spitter.getFullName());
jdbcOperations.update(SQL_INSERT_SPITTER, map);
}
因为命名参数需要通过java.util.Map进行绑定,所以需要将参数放进Map中。
使用事务
因为采用JavaConfig得方式配置Spring,所以对于事务得处理也需要通过Java代码的方式来声明,至于使用,还是与XML得方式一样来使用即可,先来回顾一下XML中配置事务的方式(使用事务注解,而不是AOP配置事务):
- 与平台相关的事务管理器
- 开启事务注解驱动:<tx:annotation-driven transaction-manager="transactionManage"/>
- 在需要事务的方法上使用@Transactional
Java代码的方式也是按照这个步骤去进行的,首先,我们配置事务管理器,JDBC和MyBatis都是使用数据源的事务管理(DataSourceTransactionManager),Hibernate和JPA使用分别各自的事务管理器(HibernateTransactionManager, JpaTransactionManager)。 因为这里使用JDBC就用DataSourceTransactionManager了
//注册事务管理器在容器中
@Bean
public PlatformTransactionManager transactionManager() throws Exception{
return new DataSourceTransactionManager(dataSource());
}
需要将数据源交给事务管理器,这样管理器可以控制commit或rollback
接下来在配置类上启用 @EnableTransactionManagement 表示开启事务注解驱动
@EnableTransactionManagement
@ComponentScan("cn.lynu")
@Configuration
public class TxConfig {
最后在需要事务的方法上使用@Transactional注解即可,使用方法与XML的配置没有什么不同。
Spring中使用JDBC的更多相关文章
- 【转】在Spring中基于JDBC进行数据访问时怎么控制超时
http://www.myexception.cn/database/1651797.html 在Spring中基于JDBC进行数据访问时如何控制超时 超时分类 超时根据作用域可做如下层级划分: Tr ...
- spring框架总结(04)----介绍的是Spring中的JDBC模板
1.1 Jdbc模板概述 它是spring框架中提供的一个对象,是对原始Jdbc API对象的简单封装.spring框架为我们提供了很多的操作模板类,入下图所示: 我们今天的主角在spring-jd ...
- Spring框架学习(3)spring中使用jdbc
内容源自:spring中使用jdbc spring dao层中对jdbc进行了封装,使用模板模式的设计模式,通过ioc被动注入的方式将jdbcTemplate这个模板类注入到数据对象中,进行数据库操作 ...
- 在Spring中配置jdbc为什么不能用${username}问题
楼主在spring中配置jdbc时,引用的是dbcp.jar包,在dataSource.properties配置文件中,有mysql用户名,楼主自然的选择了使用username,密码是root, 然后 ...
- Spring 中的 JDBC 事务
Spring 对 JDBC 的支持 JdbcTemplate 简介 •为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架. • ...
- Spring中的JDBC操作
一.Spring模板JdbcTemplate 为了使 JDBC 更加易于使用, Spring 在 JDBC API 上定义了一个抽象层, 以此建立一个 JDBC 存取框架JdbcTemplate. 作 ...
- Spring中的Jdbc事务管理
Spring提供了对事务的声明式事务管理,只需要在配置文件中做一些配置,即可把操作纳入到事务管理当中,解除了和代码的耦合. Spring声明式事务管理,核心实现就是基于Aop. Spring声明式事务 ...
- Spring中的JDBC模板类入门
1.Spring框架中提供了很多持久层的模板类来简化编程,使用模板类编写程序会变的简单 2.提供了JDBC模板,Spring框架提供的 *JdbcTemplate类 3.Spring框架可以整合Hib ...
- 在Spring中基于JDBC进行数据访问时如何控制超时
超时分类 超时根据作用域可做如下层级划分: Transaction Timeout > Statement Timeout > JDBC Driver Socket Timeout Tra ...
随机推荐
- 创建 shiny 应用程序
R 本身是一个优秀的数据分析和数据可视化平台.然而,我们通常不会将 R 和分析脚本提供给客户,让客户自己运行.数据分析的结果不仅可以在 HTML 网页.PDF 文档或 Word 文档中显示,还可以呈现 ...
- Angular2 表单验证相关
angular4响应式表单与校验http://blog.csdn.net/xiagh/article/details/78360845?locationNum=10&fps=1 How to ...
- **优化--后端**: 计数缓存counter_cache; rack-mini-profiler(2300🌟) ; bullet(5000✨):侦测N+1query
rack-mini-profiler 这个 gem,可以永远显示网页的加载时间.(2300✨)开发环境和产品环境都可以用.(生成非常详细的报告) development环境,直接使用gem 'rack ...
- telent服务搭建并远程连接
一.Telnet协议 Telnet协议是TCP/IP协议族中的一种,在网络层协议中它属于应用层协议,是Internet远程登陆服务的标准协议.可以使用本地计算机远程连接服务器,从而能够把本地用户所使用 ...
- 彻底解决WP的TextBox中文字过长显示不出来的问题
文字如果过长的话在TextBox中会显示不完全,这个大家都知道了,后来有人做了ExTextblock增强控件,大部分文字是可以显示出来了,不过,在某些情况下还是会有显示不全的情况. 这个时候一个解决方 ...
- 学习笔记20151211——AXI4 STREAM DATA FIFO
AXI4 STREAM DATA FIFO是输入输出接口均为AXIS接口的数据缓存器,和其他fifo一样是先进先出形式.可以在跨时钟域的应用中用于数据缓冲,避免亚稳态出现.支持数据的分割和数据拼接.在 ...
- 在JavaScript中进行文件处理,第三部分:处理事件和错误
译注:原文是<JavaScript高级程序设计>的作者Nicholas Zakas写的,本翻译纯属为自己学习而做,仅供参考.原文链接:这里 FileReader对象用来读取浏览器可以访问的 ...
- 接口测试HttpClient实践20150925
用了工具做接口测试,但是对于加密数据和结果的比对,以及批量数据读取,回头还是觉得代码来更方便灵活,从excle中读取数据,构成参数,发请求,并获取返回结果和预期值比较,并将结果输出程报告,可以深入做成 ...
- [leetcode] 101. Symmetric Tree 对称树
题目大意 #!/usr/bin/env python # coding=utf-8 # Date: 2018-08-30 """ https://leetcode.com ...
- C#统计给定的文本中字符出现的次数,使用循环和递归两种方法
前几天看了一个.net程序员面试题目,题目是”统计给定的文本中字符出现的次数,使用循环和递归两种方法“. 下面是我对这个题目的解法: 1.使用循环: /// <summary> /// 使 ...