SpringJdbcTemplate
简介
Jdbc:Java Database Connectivity,指的是java连接数据库操作。
JdbcTemplate是spring提供的一组数据库操作模板,主要是用来CRUD(增删改查)操作
使用前需要在pom文件中的配置:
spring-context
spring-jdbc
spring-tx
mysql-connector-java
普通的使用方法
1.首先准备数据源:spring的内置数据源
由DriverManagerDataSource类提供
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/eesy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8");
ds.setUsername("root");
ds.setPassword("jsw135799");
2.创建JdbcTemplate对象
由JdbcTemplate提供
JdbcTemplate jt = new JdbcTemplate();
给jt设置数据源
jt.setDataSource(ds);
3.接下来就可以执行各种数据库CRUD操作
jt.execute("insert into account(name,money)value ('ccc',1000)");
改进1
问题:上面在配置数据源ds的时候,setClassName,setUrl,setUsername,setPassword方法中的参数都被写死,不利于日后的代码维护或修改。
解决方案:DataSource和JdbcTemplate配置也可以在xml文件中使用Ioc的方法实现:
<!--配置JdbcTemplate-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置数据源-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/eesy?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8"></property>
<property name="username" value="root"></property>
<property name="password" value="jsw135799"></property>
</bean>
此时在java文件中就可以直接从Spring的Bean中获取容器:
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
jt.execute("insert into account(name,money)value ('ddd',222)");
}
JdbcTemplate的CRUD操作
Jdbc增删改都是使用update方法,查询使用query方法
注意JdbcTemplate中的query方法和dbutils中的QueryRunner方法的异同
dbutils中的query:public T query(String sql, ResultSetHandler rsh, Object… parans)
JdbcTemplate中的query:
dbutils中的query方法有一个,返回一个泛型T,而JdbcTemplate中有多个query方法,可以返回泛型,也可以返回集合等。
也就是说JdbcTemplate中的query是通过不同的query方法来返回,而dbutils中的query方法是靠ResultSetHandler中的返回值来决定返回的类型
public class JdbcTemplateDemo3 {
public static void main(String[] args) {
//1.获取容器
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.获取对象
JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
//3.执行操作
//保存
jt.update("insert into account (name,money)value (?,?)","eee",3333f);
//更新
jt.update("update account set name=?,money=? where id=?","test",4567,12);
//删除
jt.update("delete from account where id=?",12);
//查询所有
List<Account> accounts = jt.query("select * from account where money>?",new AccountRowMapper(),800f);//第二个参数使用的是自己创建的一个RowMapper来实现的
//List<Account> accounts = jt.query("select * from account where money>?",new BeanPropertyRowMapper<Account>(Account.class),800f);//可以使用spring中提供的BeanPropertyRowMapper方法来实现对返回值的封装
for(Account account : accounts){
System.out.println(account);
}
//查询一个
List<Account> accounts = jt.query("select * from account where id=?",new BeanPropertyRowMapper<Account>(Account.class),4);
System.out.println(accounts.isEmpty()?"没有内容":accounts.get(0));//用二元运算符判断是否为空
//查询返回一行一列(使用聚合函数,但不加group by字句)
Long count = jt.queryForObject("select count(*) from account where money>?",Long.class,1000f);
System.out.println(count);
}
}
在上面代码中的查询所有功能中,在执行完查询操作之后,是会返回一个结果集的,所以query方法中第二个参数用来接收结果集。这个参数可以是自己创建的一个RowMapper类实现,也可以用spring中提供的BeanPropertyRowMapper方法来实现。如果需要自己写RowMapper:
/**
* 定义Account的封装策略
*/
class AccountRowMapper implements RowMapper<Account>{
/**
* 把结果集中的数据封装到Account中,然后由spring把每个Account加到集合中
* @param resultSet
* @param i
* @return
* @throws SQLException
*/
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account account = new Account();
account.setId(resultSet.getInt("id"));
account.setName(resultSet.getString("name"));
account.setMoney(resultSet.getFloat("money"));
return account;
}
}
不过一般我们都使用spring中提供的BeanPropertyRowMapper来封装返回值
在查询返回一行一列方法中,使用的是queryForObject方法,该方法的第二个参数要求是返回类型的字节码,示例中返回的是Long类型。也可以用Integer类型。但是要注意接收的变量要能包容返回值。比如返回值是一个大于Integer类型的数,用Integer来接收就会报错。一般这种情况我们就直接用Long来接收。
改进2
问题:上面的示例中CRUD方法都写在main函数中,实际开发中我们肯定是要写在Dao中的,而通常我们一个项目会有多个Dao方法实现,而每个Dao实现类都需要获取JdbcTemplate:
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
这就造成代码重复。
解决方法:抽取重复代码,放入一个专门的类中,我们命名为JdbcDaoSupport
public class JdbcDaoSupport {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
}
同时其他的Dao实现类需要extends继承该类,并且用Support类中的super.getJdbcTemplate()方法代替原本的jdbcTemplate:
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao{
...
}
改进3
可以在刚刚的support类中加多两个方法:
/**
* 此类用于抽取Dao中的重复代码
*/
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);
}
}
并且去掉xml文件中对Dao的jdbcTemplate注入,改成注入一个dataSource,当我们注入dataSource时,会触发上面代码中的setDataSource方法,从而创建一个jdbcTemplate。
其实上面的JdbcDaoSupport类Spring已经给我们准备好了,我们可以不用写,直接
import org.springframework.jdbc.core.support.JdbcDaoSupport;
然后同样extends继承该类即可。
但是,如果想要用注解的方法配置Dao实现类,就必须向上面一样自己写Support类;
如果继承Spring给我们准备好的Support类,因为它属于spring提供的jar包中的代码,我们是只读模式,它给提供的注解是@Nullable无属性,所以无法使用注解。
总结:如果想要使用XML文件配置,可以选择继承spring提供的support类;如果想要使用注解配置,则需要自己写一个support。