spring原生jdbcTemplate用起来有多爽
现在相比大部分的java开发工作者连接数据库最多的就是使用hibernate和mybatis,直到前段时间我接触到了某些大佬的项目,发现jdbcTemplate真的很好用。
分析
从最开始,我就对hibernate和mybatis非常的不满,但是奈何水平有限,没办法自己开发一个框架,无奈用着mybatis。我个人认为:
hibernate框架,开发简单,自动生成sql,甚至可以自动生成表结构。虽然简单,但是正因为如此,我根本不知道它给我生成的代码是什么样的。虽然有createQuery()可以自定义sql查询,但是update和delete就很难受,需要先自定义sql查询出来,再根据id执行update和delete,这可太呆了。
mybatis框架,最难受的是需要写xml,这可太难受了,我要是数据库有变化,还得更新一下数据库,再更新一下对象类,再更新一下xml,这可太难受了。虽然说有mybatis-plus可以自定义稍复杂的sql,但是再复杂一点的sql,什么join、with子表之类的,似乎也不太行。
我就想能即不写对象字段和数据库字段对应的xml,也不写对代码侵入行比较强的注解,而且用起来非常简单,执行的时候,能清楚的直到每一步在干什么,没有内部自己搞一堆事情,同时能自己写sql提高sql编写能力。有没有这样的?原本我觉得肯定没有啊,我要求这么多。现在,我总于发现了:spring原生jdbcTemplate。
使用方式
需要亿点开发
第一步,直接就开始开发JdbcTemplateProxy
public class JdbcTemplateProxy {
private final JdbcTemplate jdbcTemplate;
public JdbcTemplateProxy(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
// 这个方法的作用,同xml文件中对象字段和数据库字段对应的代码
public NamedParameterJdbcTemplate getNamedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(getJdbcTemplate());
}
// 这个方法主要用于判断要执行的sql查询是简单对象还是自定义的bean,因为自定义对象的查询需要有属性映射,不太一样
private <T> boolean isPrim(Class<T> clazz) {
return clazz == String.class || clazz == Byte.class || clazz == Short.class || clazz == Integer.class
|| clazz == Long.class || clazz == Float.class || clazz == Double.class || clazz == Character.class
|| clazz == Boolean.class;
}
// 这里写一些自定义方法,下文讲到
}
原生的jdbcTemplate虽好,但易用性当然是不高的啦,为了让它变得易用,自己写一个jdbcTemplateProxy类,封装了jdbcTemplate,包含所有jdbcTemplate原生特性,并能够自定义一些方法,高度灵活。能够干自定义什么方法呢?
/**
* 查询对象, 直接以对象做参数
*/
public <T> T queryForObject(String sql, Object param, Class<T> clazz) {
if (isPrim(clazz)) {
return this.getNamedParameterJdbcTemplate()
.queryForObject(sql, new MyBeanPropertySqlParameterSource(param), clazz);
} else {
return this.getNamedParameterJdbcTemplate()
.queryForObject(sql, new MyBeanPropertySqlParameterSource(param),
BeanPropertyRowMapper.newInstance(clazz));
}
}
/**
* 查询对象, 自定义map参数
*/
public <T> T queryForObject(String sql, Map<String, ?> param, Class<T> clazz) {
if (isPrim(clazz)) {
return this.getNamedParameterJdbcTemplate().queryForObject(sql, new MyMapSqlParameterSource(param), clazz);
} else {
return this.getNamedParameterJdbcTemplate()
.queryForObject(sql, new MapSqlParameterSource(param), BeanPropertyRowMapper.newInstance(clazz));
}
}
/**
* 查询列表, 以对象做参数
*/
public <T> List<T> queryForList(String sql, Object param, Class<T> clazz) {
if (isPrim(clazz)) {
return this.getNamedParameterJdbcTemplate()
.queryForList(sql, new MyBeanPropertySqlParameterSource(param), clazz);
} else {
return this.getNamedParameterJdbcTemplate()
.query(sql, new MyBeanPropertySqlParameterSource(param), BeanPropertyRowMapper.newInstance(clazz));
}
}
/**
* 查询列表, 自定义map参数
*/
public <T> List<T> queryForList(String sql, Map<String, ?> param, Class<T> clazz) {
if (isPrim(clazz)) {
return this.getNamedParameterJdbcTemplate().queryForList(sql, new MyMapSqlParameterSource(param), clazz);
} else {
return this.getNamedParameterJdbcTemplate()
.query(sql, new MapSqlParameterSource(param), BeanPropertyRowMapper.newInstance(clazz));
}
}
/**
* 更新, 对象做参数
*/
public <T> void update(String sql, T params) {
SqlParameterSource paramSource = new MyBeanPropertySqlParameterSource(params);
this.getNamedParameterJdbcTemplate().update(sql, paramSource);
}
/**
* 更新, 自定义map做参数
*/
public void update(String sql, Map<String, ?> params) {
this.getNamedParameterJdbcTemplate().update(sql, new MyMapSqlParameterSource(params));
}
/**
* 批量更新, 对象做参数
*/
public <T> void batchUpdate(String sql, List<T> list) {
SqlParameterSource[] paramSource = this.createBatch(list.toArray());
this.getNamedParameterJdbcTemplate().batchUpdate(sql, paramSource);
}
/**
* 更新, 自定义map做参数
*/
public <V> void batchUpdate(String sql, Map<String, V>[] list) {
SqlParameterSource[] paramSource = this.createBatch(list);
this.getNamedParameterJdbcTemplate().batchUpdate(sql, paramSource);
}
这是最常用的,还可以自定义更多的定制化方法。参数:
- sql,自己写的sql语句
- param,查询参数
- clazz,查询结果的对象类(这就等于是写了Mapper.xml了)
有什么好处呢
比如有一个User对象:user,你想查id=user.id的User或者name=user.name的User,你可以使用框架或者写两个方法如下:
selectById(String id)
selectByName(String name)
而现在,则不然,现在调用以对象作为参数的queryForObject()是这样:
selectById(User user)
selectByName(User user)
查User对象,不管是以什么查询,查询的参数都可以是User对象,只是根据sql不同,会自动匹配对象中的属性作为参数,降低了代码的耦合程度。当然你要是想id作为参数,也可以用以自定义map作为参数的queryForObject()。
第二步,配置Datasource和JdbcTemplateProxy
@Configuration
public class DataSourceConfig {
@Bean(name = "oracleDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid")
public DataSource oracleDataSource() {
return new DruidDataSource();
}
@Bean("oracleJdbcTemplateProxy")
public JdbcTemplateProxy oracleJdbcTemplateProxy() {
DataSource oracleDatasource = oracleDataSource();
return new JdbcTemplateProxy(oracleDatasource);
}
}
用起来
使用起来是这样的(以查询一个对象为例):
// 注入proxy
@Resource(name = "oracleJdbcTemplateProxy")
private JdbcTemplateProxy proxy;
public User queryById(String id) {
String sql = "select id, name from user where id = :id";
Map<String, String> param = new HashMap<>();
param.put("id", id);
proxy.queryForObject(sql, param, User.class);
}
不用写xml,不用写注解,无代码侵入,sql自定义,方法可复用,多种参数可选,灵活性高。刚开始使用的时候感觉这什么玩意儿,搞这么一堆,后来,发现是真的舒服,简单易用不说,开发的时候,比较复杂的sql,能够debug看sql和参数,别提多高效。