一、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学习笔记的更多相关文章

  1. JdbcTemplate学习笔记

    JdbcTemplate学习笔记 1.使用JdbcTemplate的execute()方法执行SQL语句 Java 代码 jdbcTemplate.execute("CREATE TABLE ...

  2. Spring实战第一章学习笔记

    Spring实战第一章学习笔记 Java开发的简化 为了降低Java开发的复杂性,Spring采取了以下四种策略: 基于POJO的轻量级和最小侵入性编程: 通过依赖注入和面向接口实现松耦合: 基于切面 ...

  3. Spring实战第八章学习笔记————使用Spring Web Flow

    Spring实战第八章学习笔记----使用Spring Web Flow Spring Web Flow是一个Web框架,它适用于元素按规定流程运行的程序. 其实我们可以使用任何WEB框架写流程化的应 ...

  4. #Spring实战第二章学习笔记————装配Bean

    Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...

  5. Spring Cloud微服务学习笔记

    Spring Cloud微服务学习笔记 SOA->Dubbo 微服务架构->Spring Cloud提供了一个一站式的微服务解决方案 第一部分 微服务架构 1 互联网应用架构发展 那些迫使 ...

  6. spring data jpa入门学习

    本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...

  7. Spring Data Jpa 入门学习

    本文主要讲解 springData Jpa 入门相关知识, 了解JPA规范与Jpa的实现,搭建springboot+dpringdata jpa环境实现基础增删改操作,适合新手学习,老鸟绕道~ 1. ...

  8. Spring jdbctemplate学习笔记

    /*List<?> config = getDB(" select t.datavalue from sys_config t where t.configid = '15' & ...

  9. Spring 4.0.2 学习笔记(2) - 自动注入及properties文件的使用

    接上一篇继续, 学习了基本的注入使用后,可能有人会跟我一样觉得有点不爽,Programmer的每个Field,至少要有一个setter,这样spring配置文件中才能用<property> ...

随机推荐

  1. Java--异常与字符串

    1.处理异常 try-catch以及try-catch-finally try{ //一些会抛出的异常 }catch(Exception e){ //处理该异常的代码块 }catch(Exceptio ...

  2. L99

    You're not obligated to win. You're obligated to keep trying.你不一定要获胜,但你必须不断尝试.He announced an expans ...

  3. 转载 解决Android与服务器交互大容量数据问题

    对于目前的状况来说,移动终端的网络状况没有PC网络状况那么理想.在一个Android应用中,如果需要接收来自服务器的大容量数据,那么就不得不考虑客户的流量问题.本文根据笔者的一个项目实战经验出发,解决 ...

  4. OpenAL播放pcm或wav数据流-windows/ios/android(一)

    OpenAL播放pcm或wav数据流-windows/iOS/Android(一)   最近在研究渲染问题,本文采用openal做pcm和wav数据流播放,并非本地文件,demo是windows的,i ...

  5. hdu 4372 Count the Buildings —— 思路+第一类斯特林数

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4372 首先,最高的会被看见: 然后考虑剩下 \( x+y-2 \) 个被看见的,每个带了一群被它挡住的楼, ...

  6. Poj 1458 Common Subsequence(LCS)

    一.Description A subsequence of a given sequence is the given sequence with some elements (possible n ...

  7. 使用Sed抽取MySQL安装文档的目录及行号

    sed -nr  -e '/^2.|^shell/=' -e '/^2.|^shell/p' INSTALL-SOURCE |awk '{if (NR%2==1) x=$1; else printf ...

  8. modbus读输入状态与读线圈状态的区别?

    01 读线圈状态 描述 读从机离散量输出口的 ON/OFF 状态,不支持广播.附录B列出由不同控制器型号支持最大的参数清单. 查询 查询信息规定了要读的起始线圈和线圈量,线圈的起始地址为零,1-16个 ...

  9. sql中in和exist语句的区别?(补充了left join和right join)

    in和exists(摘录自百度)in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询. 如果两个表中一个较小,一个是大表,则子查询表大的用exi ...

  10. linux strace-跟踪进程的系统调用或是信号产生情况,lstrace-跟踪己丑年调用库函数情况,进程跟踪调试命令

    本工具可以用来做大多数排除,比如mount一个NFS,很慢,找不出原因,我们可以使用strace命令来跟中mount这个经常所有的调用过程. strace 命令是一种强大的工具,它能够显示所有由用户空 ...