spring data之JDBCTemplate学习笔记
一、spring 数据访问哲学
1、为避免持久化的逻辑分散在程序的各个组件中,数据访问的功能应到放到一个或多个专注于此的组件中,一般称之为数据访问对象(data access object,DAO)。
2、良好的的Repository应以接口的形式向外暴露出去,服务对象通过接口访问Repository对象,这样做可以使服务对象很方便的进行测试,甚至可以创建mock来进行测试。
3、数据访问层应该是与持久化技术无关的方式来进行访问的,这样可以使得切换底层的持久层框架对程序的其他地方所带来的影响最小。

服务对象与Repository之间的关系,服务对象不会处理数据访问,而是将其委托给Repository。
二、spring 的数据访问异常体系
在使用原生的JDBC访问数据时,应用程序必须去捕获JDBC抛出的异常SQLException,而且大多数情况下,异常不会告诉你哪里出了问题、如何处理。
spring JDBC提供的数据访问异常体系解决了这两个问题,spring提供了很多数据访问异常,分别描述了他们抛出时所对应的问题。spring为读取和写入数据的几乎所有错误都提供了异常。而且spring 提供的异常均继承自DataAccessException,该异常为运行时异常,所以在代码中不必强制去捕获。
这样做的好处是:
- 开发者可以从底层繁琐复杂的技术细节中解脱出来。
- 开发者可以选择自己感兴趣的异常进行处理 。
常见的spring异常
| 异常类 | 说明 |
| CleanupFailureDataAccessException | 执行 DAO 操作成功,但在释放数据资源时发生异常,如关闭 Connection 时发生异常。 |
| ConcurrencyFailureException | 并发地操作数据时发生异常,如无法获取乐观锁或悲观锁时、死锁引发的失败等场景。 |
| DataAccessResourceFailureException | 访问数据资源失败,如无法获取数据连接,无法获取 Hibernate 的会话等场景。 |
| DataRetrievalFailureException | 获取数据失败,如找不到对应主键的数据或使用了错误的列索引等场景。 |
| DataSourceLookupFailureException | 无法从 JNDI 中查找到数据源。 |
| DataIntegrityViolationException | 数据操作违反了数据一致性限制时抛出,如插入重复的主键或引用不存在的外键场景。 |
| InvalidDataAccessApiUsageException | 不正确地调用某一种持久化技术时抛出,如在 Spring JDBC 中查询对象在调用前没有事先进行编译操作,就会抛出该异常。这种异常主要是因为不正确地使用持久化技术而产生的。 |
| InvalidDataAccessResourceUsageException | 在访问数据源时使用了不正确的方法时抛出,如写错 SQL 语句。 |
| PermissionDeniedDataAccessException | 数据访问权限不足时抛出。如仅拥有只读权限却试图更改数 |
| UncategorizedDataAccessException | 其它未被分类的异常。 |
| ................ | ................. |
为了使用spring 的数据访问异常,必须使用spring支持的数据访问模板。
三、数据访问模板
模板方法将过程中与特定实现相关的部分委托给接口,接口的不同实现定义了过程中的具体行为。(设计模式中模板模式的案例?没看过源码,不确定是不是
spring在进行数据访问过程中将固定的和可变的明确划分为两个不同的类:模板和回调。模板管理过程中固定的部分,回调处理自定义的数据访问代码。

模板与回调的职责,模板类处理固定部分:事物控制、管理资源以及异常处理,回调处理语句、绑定参数以及整理结果集。
如果直接使用JDBC,可以使用JdbcTemplate,若使用ORM框架,可以考虑使用JpaTemplate或者HibernateTemplate等。
| 模板类 | 用途 |
| jdbc.core.JdbcTemplate | JDBC链接 |
| jdbc.core.namedparam.NamedParameterJdbcTemplate | 支持命名参数的JDBC链接 |
| orm.ibatis.SqlMapClientTemplate | IBATIS SqlMap客户端 |
| orm.Jpa.JpaTemplate | java持久化API的实体管理器 |
| ............ | ........... |
spring 提供的数据访问模板
四、数据源的配置
spring多种数据源配置方式
- JDBC驱动程序定义的数据源
- JNDI查找的数据源
- 连接池的数据源
考虑到现在基本都是spring boot的天下了,基本也不使用XML配置了,故此仅给出java配置。
1、JNDI数据源(没用过仅做记录)
java配置:
@Bean
public JndiObjectFactoryBean dataSource(){
JndiObjectFactoryBean factoryBean = new JndiObjectFactoryBean();
factoryBean.setJndiName("jdbc/myProjectDS");//指定JNDI中资源的名称。
factoryBean.setResourceRef(true);//若运行在java服务器中需要设置为true
factoryBean.setProxyInterface(DataSource.class);
return factoryBean;
}
2、数据源连接池
常见的数据库连接池有以下几个:
- Apache commons DBCP
- c3p0
- BoneCP
- Druid
java配置:
@Bean
public BasicDataSource dataSource(){
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("org.h2.Driver");
ds.setUrl("jdbc:h2:tcp://localhost/~/test");
ds.setUsername("root");
ds.setPassword("123");
ds.setInitialSize(5);
ds.setMaxActive(10);
return ds;
}
3、基于JDBC的驱动的数据源
这种数据源是最简单的配置方式,spring 提供了三个这样的数据源类
- DriverManagerDataSource:在每个连接请求时都会返回一个新建的链接
- simpleDriverDataSOurce:与DriverManagerDataSource类似,不同的是他直接使用JDBC驱动
- SingleConnectionDataSource:在每个连接请求时都会返回同一个连接,可认为是只有一个连接的池,该类不适合多线程的应用程序。
@Bean
public DataSource dataSource(){
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("org.mysql.Driver");
driverManagerDataSource.setUrl("url");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("1");
return driverManagerDataSource;
}
4、嵌入式数据源,H2
嵌入式数据源作为应用的一部分运行,而不是独立的数据库服务器,对生产环境没有啥用处,但对开发和测试而言是非常好的方案
@Bean
public DataSource dataSource(){
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("classpath:schema.sql")
.addScript("classpath:test-data.sql")
.build();
}
五、使用JDBC模板
spring共提供三个JDBC模板:
- JdbcTemplate最基本的springJDBC模板,支持简单的JDBC数据库访问功能以及基于索引的参数查询
- NamedParameterJdbcTemplate:该模板可以将值以命名参数的形式绑定到SQL中,而非简单的索引值。
- SimpleJdbcTepmlate:已被废弃,不做介绍。
1、首先需要配置一个JDBCTemplate,只需为期设置DataSource即可。
代码如下
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
2、编写数据访问相关接口及实现类
图省事,省去了接口类,实际使用过程中自行添加。
UserRepository类
@Repository
public class UserRepository {
private JdbcOperations jdbcOperations;
@Autowired
public UserRepository(JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
} public void addUser(User user){
jdbcOperations.update("insert into user (username,password,email) values(?,?,?) ",
user.getUsername(),user.getPassword(),user.getEmail());
}
public User findUser(String id){
return jdbcOperations.queryForObject("select * from user where id = "+id,(resultSet, i) -> User.builder()
.username(resultSet.getString("username"))
.password(resultSet.getString("password"))
.email(resultSet.getString("email"))
.id(resultSet.getLong("id"))
.build());
}
}
UserController类:
@RestController
public class UserController {
private final UserRepository repository; @Autowired
public UserController(UserRepository repository) {
this.repository = repository;
} @GetMapping("/addUser")
public String aa(){
repository.addUser(User.builder()
.email("abc@aa.com")
.username("tom")
.password("123456")
.build());
return "succ";
} @GetMapping("/query/{id}")
public User queryUser(@PathVariable String id){
return repository.findUser(id);
}
}
NamedParameterJdbcTemplate简单使用:
配置
@Bean
public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource){
return new NamedParameterJdbcTemplate(dataSource);
}
使用map绑定参数
public void addUser(User user){
Map<String,Object> data = new HashMap<>(8);
data.put("username","zhangsan");
data.put("password","123456");
data.put("email","asd@asd.com");
data.put("id", 123432);
jdbcOperations.update("insert into user(username,password,email,id) values (:username,:password,:email,:id)",data);
}
JdbcOperations API(下次有空了总结哈):https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/core/JdbcOperations.html
Z、参考资料
https://blog.csdn.net/deniro_li/article/details/82820966
spring data之JDBCTemplate学习笔记的更多相关文章
- JdbcTemplate学习笔记
JdbcTemplate学习笔记 1.使用JdbcTemplate的execute()方法执行SQL语句 Java 代码 jdbcTemplate.execute("CREATE TABLE ...
- Spring实战第一章学习笔记
Spring实战第一章学习笔记 Java开发的简化 为了降低Java开发的复杂性,Spring采取了以下四种策略: 基于POJO的轻量级和最小侵入性编程: 通过依赖注入和面向接口实现松耦合: 基于切面 ...
- Spring实战第八章学习笔记————使用Spring Web Flow
Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...
- #Spring实战第二章学习笔记————装配Bean
Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...
- Spring Cloud微服务学习笔记
Spring Cloud微服务学习笔记 SOA->Dubbo 微服务架构->Spring Cloud提供了一个一站式的微服务解决方案 第一部分 微服务架构 1 互联网应用架构发展 那些迫使 ...
- spring data jpa入门学习
本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...
- Spring Data Jpa 入门学习
本文主要讲解 springData Jpa 入门相关知识, 了解JPA规范与Jpa的实现,搭建springboot+dpringdata jpa环境实现基础增删改操作,适合新手学习,老鸟绕道~ 1. ...
- Spring jdbctemplate学习笔记
/*List<?> config = getDB(" select t.datavalue from sys_config t where t.configid = '15' & ...
- Spring 4.0.2 学习笔记(2) - 自动注入及properties文件的使用
接上一篇继续, 学习了基本的注入使用后,可能有人会跟我一样觉得有点不爽,Programmer的每个Field,至少要有一个setter,这样spring配置文件中才能用<property> ...
随机推荐
- Javascript-- jQuery事件篇(2)
jQuery表单事件之blur与focus事件 单处理事件focusin事件与focusout事件,同样用于处理表单焦点的事件还有blur与focus事件 它们之间的本质区别: 是否支持冒泡处理 举个 ...
- mfc创建文档视图过程
一.如何创建文档视图界面: 创建新的文档视图界面,只需要调用CDocTemplate::OpenDocumentFile(strpath)即可.(strpath为要打开的文档路径,如果是NULL,则生 ...
- eslipse 修改tomcat server location 解决HTTP Status 404 – Not Found
Eclipse中tomcat service设置选择window ----show view---services可以看到服务的面板双击tomcat进入配置界面Service Locations(Sp ...
- 【遍历二叉树】08判断两个二叉树是否相同【Same Tree】
迭代版本用的是二叉树的DFS,中的root->right->left +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ...
- 解决苹果手机Safari浏览器下 字体显示为 蓝色的 问题
解决苹果手机 Safari浏览器下 字体显示为蓝色的 问题 近期测试同学测试,wap站上,底部文字在苹果8上面 ,使用 Safari浏览器打开,一直显示 蓝色字体 其他正常,寻找半天无解,最后 阳 ...
- [Luogu3960][NOIP2017]列队
luogu sol 震惊!\(NOIP\)居然也出数据结构! 话说回来,其实只需要对每一行的前\(m-1\)个人维护一个数据结构,然后对最后一列的\(m\)个人也维护一个数据结构就好了.具体的话写平衡 ...
- 删除文件时提示 你需要来自system的权限才能对此文件夹进行更改
问题描述: 我的计算机是Win7 x64操作系统,在我的计算机的F盘中,不知道什么时候多了个“12e4k69m762nzcgt8zx”这样一个文件夹,应该是某个软件自己创建并留下的文件夹,想删除掉则提 ...
- GPRS模块用TCP实现MQTT协议(基于SIM900A)
mqtt部分: int strlen(char *str) { int len = 0; while (*str != '\0') { len++; str++; } return len; } // ...
- redis的read error on connection错误解决
昨日,公司php调用redis报错:read error on connection 2015-01-29 23:59:050.13330000,redis存放的是用户session. 在网上查询,大 ...
- python 字典 get 小例子
语法 get()方法语法: dict.get(key, default=None) 参数 key -- 字典中要查找的键. default -- 如果指定键的值不存在时,返回该默认值值. 返回值 返回 ...