https://www.bilibili.com/video/av47952931
p67~71
持久层总图
Spring中的JdbcTemplate
作用:和数据库交互,实现对表的CRUD操作
JdbcTemplate与DbUtils DbUtils是Apache提供的一个对JDBC进行简单封装的开源工具类库,主要有
org.apache.commons.dbutils.QueryRunner — 核心类,执行SQL查询以处理结果集(线程安全)
org.apache.commons.dbutils.ResultSetHandler — 结果集封装器
org.apache.commons.dbutils.DbUtils — 提供如加载驱动、关闭连接、事务提交、回滚等常规工作的工具类
JdbcTemplate是Spring提供的一个对象,是对原始Jdbc API对象的简单封装,基本方法:
execute方法
update与batchUpdate方法
query与queryXXX方法
call方法
DbUtils导的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <dependency > <groupId > commons-dbutils</groupId > <artifactId > commons-dbutils</artifactId > <version > 1.4</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 8.0.16</version > </dependency > <dependency > <groupId > com.mchange</groupId > <artifactId > c3p0</artifactId > <version > 0.9.5.2</version > </dependency >
JdbcTemplate导的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <dependency > <groupId > org.springframework</groupId > <artifactId > spring-jdbc</artifactId > <version > 5.0.2.RELEASE</version > </dependency > <dependency > <groupId > org.springframework</groupId > <artifactId > spring-tx</artifactId > <version > 5.0.2.RELEASE</version > </dependency > <dependency > <groupId > mysql</groupId > <artifactId > mysql-connector-java</artifactId > <version > 5.1.6</version > </dependency >
表的实体类 实现Serializable接口
1 2 3 4 5 6 7 8 9 10 11 12 public class Account implements Serializable { private Integer id; private String name; private Float money; }
JdbcTemplate的最基本用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class JdbcTemplateDemo1 { public static void main (String[] args) { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("com.mysql.jdbc.Driver" ); ds.setUrl("jdbc:mysql://localhost:3306/groot?characterEncoding=utf8" ); ds.setUsername("root" ); ds.setPassword("iamgroot" ); JdbcTemplate jt = new JdbcTemplate(); jt.setDataSource(ds); jt.execute("insert into account(name,money) values('ccc',1000)" ); } }
执行,没有问题
但是这样写数据库的配置都写死了,而且用了很多set、new
都可以通过IoC配置
IoC配置 这里dataSource暂时先用Spring内置的(id=”dataSource”)
1 2 3 4 5 6 7 8 9 10 11 12 public class JdbcTemplateDemo2 { public static void main (String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml" ); JdbcTemplate jt = ac.getBean("jdbcTemplate" ,JdbcTemplate.class); jt.execute("insert into account(name,money)values('ddd',2222)" ); } }
也没问题
使用JdbcTemplate实现基本的CRUD 增删改都是update方法
1 2 3 4 5 6 7 8 jt.update("insert into account(name,money)values(?,?)" ,"eee" ,3333f ); jt.update("update account set name=?,money=? where id=?" ,"test" ,4567 ,7 ); jt.update("delete from account where id=?" ,8 );
查询是query
query有很多很多很多重载的方法,找的时候关注两个点:我们有什么(参数)、我们要什么(返回值)
比如有sql语句、参数,要返回一个List,筛选出来基本就剩2个了,它们一个要传Object[] args,一个是Object… args,是针对不同版本的(前者所有版本可用,后者jdk5之后支持可变参数可用)
第一个方法:
1 2 List<Account> accounts = jt.query("select * from account where money > ?" ,new AccountRowMapper(),1000f );
需要写一个AccountRowMapper类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class AccountRowMapper implements RowMapper <Account > { public Account mapRow (ResultSet rs, int rowNum) throws SQLException { Account account = new Account(); account.setId(rs.getInt("id" )); account.setName(rs.getString("name" )); account.setMoney(rs.getFloat("money" )); return account; } }
此时问题来了,对比dbutils中的QueryRunner
不同的只有ResultSetHandler和AccountRowMapper,从封装的角度作用是一样的
以前是用的dbutils提供的beanListHandler实现的
难道机智的Spring没有这个实现吗还要自己写?
显然必须有 -> BeanPropertyRowMapper
1 2 3 4 5 6 List<Account> accounts = jt.query("select * from account where money > ?" ,new BeanPropertyRowMapper<Account>(Account.class),1000f ); for (Account account : accounts){ System.out.println(account); }
能查所有了,查一个也差不多(实际使用BeanPropertyRowMapper比较多)
1 2 3 List<Account> accounts = jt.query("select * from account where id = ?" ,new BeanPropertyRowMapper<Account>(Account.class),3 ); System.out.println(accounts.isEmpty()? "没有内容" :accounts.get(0 ));
还有聚合
1 2 3 Long count = jt.queryForObject("select count(*) from account where money > ?" ,Long.class,1000f ); System.out.println(count);
第二个参数用来指定返回类型(前提是能转,为防溢出一般用Long接收)
JdbcTemplate在Dao中的使用 写一个IAccountDao接口,实现类中用上面的方法完成功能即可
JdbcDaoSupport的使用 有一个问题是,如果实际开发中有多个Dao,每个实现类中都要获取JdbcTemplate
1 2 3 4 5 private JdbcTemplate jdbcTemplate;public void setJdbcTemplate (JdbcTemplate jdbcTemplate) { this .jdbcTemplate = jdbcTemplate; }
这段代码会重复很多次
可以写一个JdbcDaoSupport类用于抽取这段重复代码
其它DaoImp继承这个类,get其中的jdbcTemplate,dataSource也在其中设置好
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 public class JdbcDaoSupport { private JdbcTemplate jdbcTemplate; public void setJdbcTemplate (JdbcTemplate jdbcTemplate) { this .jdbcTemplate = jdbcTemplate; } public JdbcTemplate getJdbcTemplate () { return jdbcTemplate; } public void setDataSource (DataSource dataSource) { if (jdbcTemplate == null ){ jdbcTemplate = createJdbcTemplate(dataSource); } } private JdbcTemplate createJdbcTemplate (DataSource dataSource) { return new JdbcTemplate(dataSource); } }
显然,setDataSource的时候JdbcTemplate也有了
于是配置的时候就不用配JdbcTemplate了
1 2 3 4 5 6 7 8 9 10 <bean id ="accountDao" class ="com.itheima.dao.impl.AccountDaoImpl" > <property name ="dataSource" ref ="dataSource" > </property > </bean >
那么问题又来了
自己都能写出来的东西Spring显然必须有
把这个自己写的JdbcDaoSupport注释掉,还能跑,为啥呢
1 import org.springframework.jdbc.core.support.JdbcDaoSupport;
自动导入了Spring的JdbcDaoSupport
打开这个类看一下,就有JdbcTemplate,有setDataSource方法,有上面一堆
所以不需要自己写,继承就完事
继承它的目的就是在有多个Dao时去除重复代码
但是由于源码不能动,就不好通过注解配置了,自己写和直接继承的区别就在于这里,需要权衡