相关资源分享-下载可直接使用:
https://download.csdn.net/download/csdn_heliu/10736181
JdbcTemplate简介:
- spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
- JdbcTemplate主要提供以下五类方法:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
为啥要使用JdbcTemplate进行开发呢?
- Spring提供的JdbcTemplate对jdbc做了封装,大大简化了数据库的操作。
- 如果直接使用JDBC的话,需要我们加载数据库驱动、创建连接、释放连接、异常处理等一系列的动作,繁琐且代码看起来不直观。
- Spring提供的JdbcTempate能直接数据对象映射成实体类,不再需要获取ResultSet去获取值/赋值等操作,提高开发效率。
数据库相关配置:
# 数据库配置 jdbc.url=jdbc\:mysql\://localhost\:3306/test?useUnicode\=true&characterEncoding\=utf-8 jdbc.username=root jdbc.password=root jdbc.driver=com.mysql.jdbc.Driver
数据源相关配置application-datasource.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" default-lazy-init="true"> <description>数据源相关配置</description> <!-- 与上面的配置等价,下面的更容易理解 --> <!-- <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="locations"> <!– PropertyPlaceholderConfigurer类中有个locations属性,接收的是一个数组,即我们可以在下面配好多个properties文件 –> <array> <value>classpath:application.properties</value> </array> </property> </bean>--> <!-- 这些配置Spring在启动时会初始化--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="namedJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> </bean> <bean id="daoClient" class="com.heliu.base.DaoClient"> <property name="jdbcTemplate" ref="namedJdbcTemplate"/> <property name="xmlParse" ref="xmlParse"/> </bean> <bean id="xmlParse" class="com.heliu.base.XmlParse"> <property name="resources" value="classpath:sqlmaps/sqlMap_*.xml"/> </bean> </beans>
编写封装类DaoClient.java:
package com.heliu.base; import com.alibaba.fastjson.JSONObject; import com.heliu.util.FreeMakerParser; import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; import java.util.*; /** * @author HeLiu * @Description 基于jdbctemplate数据持久层操作封装 * @date 2018/7/30 10:00 */ public class DaoClient { private static final Logger logger = LoggerFactory.getLogger(DaoClient.class); private static final String INTEGER = "java.lang.Integer"; private static final String LONG = "java.lang.Long"; private static final String BIGDECIMAL = "java.math.BigDecimal"; private static List<String> TYPE_LIST = new LinkedList<>(); static { TYPE_LIST.add("java.lang.Integer"); TYPE_LIST.add("java.lang.String"); TYPE_LIST.add("java.lang.Long"); TYPE_LIST.add("java.math.BigDecimal"); } private FreeMakerParser freeMakerParser; private NamedParameterJdbcTemplate jdbcTemplate; private XmlParse xmlParse; public NamedParameterJdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public void setJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public XmlParse getXmlParse() { return xmlParse; } public void setXmlParse(XmlParse xmlParse) { this.xmlParse = xmlParse; } /** * @Description 查询单个对象 * @author HeLiu * @date 2018/7/30 10:22 */ public <T> T queryForObject(String sqlId, Object param, Class<T> clazz) { String clazzStr = clazz.getName(); Map<String, Object> paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); try { //返回一些特殊类型(Integer,String,... ...) if (TYPE_LIST.contains(clazzStr)) { return jdbcTemplate.queryForObject(sql, paramMap, clazz); } //返回指定对象,将返回参数映射到对象里面 RowMapper<T> rm = BeanPropertyRowMapper.newInstance(clazz); return jdbcTemplate.queryForObject(sql, paramMap, rm); } catch (EmptyResultDataAccessException e) { logger.info(".......databse no record ........."); return null; } } /** * @Description 查询单个对象(不要条件查询,比如查询数量... ...) * @author HeLiu * @date 2018/7/30 11:54 */ public <T> T queryForObject(String sqlId, Class<T> clazz) { return queryForObject(sqlId, new HashMap<>(), clazz); } /** * @Description 查询Map结果 * @author HeLiu * @date 2018/7/30 14:29 */ public Map<String, Object> queryForMap(String sqlId, Object param) { Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); try { return jdbcTemplate.queryForMap(sql, paramMap); } catch (EmptyResultDataAccessException e) { logger.info(".......databse no record ........."); return null; } } /** * @Description 查询多个对象 * @author HeLiu * @date 2018/7/30 17:14 */ public <T> List<T> queryForList(String sqlId, Object param, Class<T> clazz) { String clazzStr = clazz.getName(); Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); try { //jdbcTemplate查询String、Integer... ...类型query方法会报错 //所以通过调用其他方法解决 //所以在此区分一下 if (TYPE_LIST.contains(clazzStr)) { return jdbcTemplate.queryForList(sql, paramMap, clazz); } RowMapper<T> rm = BeanPropertyRowMapper.newInstance(clazz); return jdbcTemplate.query(sql, paramMap, rm); } catch (EmptyResultDataAccessException e) { logger.info(".......databse no record ........."); return null; } } /** * @Description 查询Map List * @author HeLiu * @date 2018/7/30 17:33 */ public List<Map<String, Object>> queryForList(String sqlId, Object param) { Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); try { return jdbcTemplate.queryForList(sql, paramMap); } catch (EmptyResultDataAccessException e) { logger.info(".......databse no record ........."); return null; } } /** * @Description 查询多个对象 * @author HeLiu * @date 2018/7/30 17:38 */ public <T> List<T> queryForList(String sqlId, Class<T> clazz) { return queryForList(sqlId, new HashMap<>(), clazz); } /** * @Description 保存数据,并获得主键id * @author HeLiu * @date 2018/7/30 17:57 */ public int insertAndGetId(String sqlId, Object param) { Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); MapSqlParameterSource parameters = new MapSqlParameterSource(paramMap); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql, parameters, keyHolder, new String[]{"ID"}); return keyHolder.getKey().intValue(); } /** * @Description 批量保存,并获得主键id * @author HeLiu * @date 2018/7/30 17:42 */ public List<Integer> batchInsertAndGetId(String sqlId, Object param) { Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); MapSqlParameterSource parameters = new MapSqlParameterSource(paramMap); KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(sql, parameters, keyHolder, new String[]{"ID"}); List<Integer> ids = new ArrayList<Integer>(); for (Map<String, Object> map : keyHolder.getKeyList()) { Integer id = MapUtils.getInteger(map, "GENERATED_KEY"); ids.add(id); } return ids; } /** * @Description 执行数据库操作,更新、删除、保存,返回执行成功条数 * @author HeLiu * @date 2018/7/30 18:03 */ public int excute(String sqlId, Object param) { Map paramMap = JSONObject.parseObject(JSONObject.toJSONString(param), Map.class); String sql = xmlParse.getSql(sqlId); sql = freeMakerParser.process(sql, paramMap); return jdbcTemplate.update(sql, paramMap); } }
sql解析需要的两个文件:
- XmlParse.java
package com.heliu.base; import org.apache.commons.lang3.StringUtils; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.core.io.Resource; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * @author HeLiu * @Description xml解析 * @date 2018/7/30 10:24 */ public class XmlParse implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(XmlParse.class); private Resource[] resources; public Resource[] getResources() { return resources; } public void setResources(Resource[] resources) { this.resources = resources; } public XmlParse(Resource[] resources) { this.resources = resources; } public XmlParse() { } private static final Map<String, String> sqlMap = new ConcurrentHashMap<String, String>(); public Map<String, String> initSqlMap() { try { if (null == resources || resources.length <= 0) { logger.error("没有配置sql文件"); return sqlMap; } int count = 0; for (Resource resource : resources) { logger.info("sqlmap 文件url ......{}", resource.getURL()); SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(resource.getInputStream()); Element foo = doc.getRootElement(); String namespace = foo.getAttributeValue("namespace"); if (StringUtils.isBlank(namespace)) { logger.error("sql的xml文件中,根节点没有配置namespace属性"); return sqlMap; } List<Element> childrens = foo.getChildren(); for (Element ele : childrens) { String id = ele.getAttributeValue("id"); if (StringUtils.isBlank(id)) { logger.error("sql的xml文件中,没有配置sql的 id属性"); return sqlMap; } String sqlContent = ele.getValue(); count++; sqlMap.put(namespace + "." + id, sqlContent); } } logger.info("sql 加载完成!共{}条", count); } catch (Exception e) { logger.error("解析sqlmap 异常", e); } return sqlMap; } public static String getSql(String sqlId) { return sqlMap.get(sqlId); } @Override public void afterPropertiesSet() throws Exception { initSqlMap(); } }
- FreeMakerParser.java
package com.heliu.util; import freemarker.template.Configuration; import freemarker.template.Template; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.*; import java.util.HashMap; import java.util.Map; /** * @author HeLiu * @Description freeMaker解析 * @date 2018/10/22 10:29 */ public class FreeMakerParser { private static Log logger = LogFactory.getLog(FreeMakerParser.class); private static final String DEFAULT_TEMPLATE_KEY = "default_template_key"; private static final String DEFAULT_TEMPLATE_EXPRESSION = "default_template_expression"; private static final Configuration CONFIGURER = new Configuration(); static { CONFIGURER.setClassicCompatible(true); } /** * 配置SQL表达式缓存 */ private static Map<String, Template> templateCache = new HashMap<String, Template>(); /** * 分库表达式缓存 */ private static Map<String, Template> expressionCache = new HashMap<String, Template>(); public static String process(String expression, Map<String, Object> root) { StringReader reader = null; StringWriter out = null; Template template = null; try { if (expressionCache.get(expression) != null) { template = expressionCache.get(expression); } if (template == null) { template = createTemplate(DEFAULT_TEMPLATE_EXPRESSION, new StringReader(expression)); expressionCache.put(expression, template); } out = new StringWriter(); template.process(root, out); return out.toString(); } catch (Exception e) { logger.error("freemark解析sql 异常", e); } finally { if (reader != null) { reader.close(); } try { if (out != null) { out.close(); } } catch (IOException e) { return null; } } return null; } private static Template createTemplate(String templateKey, Reader reader) throws IOException { Template template = new Template(DEFAULT_TEMPLATE_KEY, reader, CONFIGURER); template.setNumberFormat("#"); return template; } public static String process(Map<String, Object> root, String sql, String sqlId) { StringReader reader = null; StringWriter out = null; Template template = null; try { if (templateCache.get(sqlId) != null) { template = templateCache.get(sqlId); } if (template == null) { reader = new StringReader(sql); template = createTemplate(DEFAULT_TEMPLATE_KEY, reader); templateCache.put(sqlId, template); } out = new StringWriter(); template.process(root, out); return out.toString(); } catch (Exception e) { logger.error("freemark解析sql 异常", e); } finally { if (reader != null) { reader.close(); } try { if (out != null) { out.close(); } } catch (IOException e) { return null; } } return null; } /** * 模板文件解析 * * @param paramMap 参数 * @param resultFileWriter 结果文件写入器 * @param templateFileReader 模板文件读取器 * @author HeLiu * @date 2018/10/22 10:29 */ public static void process(Map<String, Object> paramMap, Writer resultFileWriter, Reader templateFileReader) { CONFIGURER.setDefaultEncoding("UTF-8");// 设置默认编码方式 try { Template template = createTemplate(DEFAULT_TEMPLATE_EXPRESSION, templateFileReader); template.process(paramMap, resultFileWriter); logger.info(".............freemark文件解析完成.........."); } catch (Exception e) { logger.error("freemark 解析异常", e); e.printStackTrace(); } } }
Dao层写法:
@Repository
public class IndexDao {
private static final Logger logger = LoggerFactory.getLogger(IndexDao.class);
@Autowired
private DaoClient daoClient;
private final String NAME_SPACE = "student."; //对应sql文件namespace
}
sql文件写法:
<?xml version="1.0" encoding="UTF-8"?>
<sqls namespace="student">
<sqlTemplate id="queryStudent"> //此处id对应方法调用的sql
<![CDATA[
//这里面编写sql语句
]]>
</sqlTemplate>
</sqls>
注意:
- 需要的jar依赖,根据需求导入,这里就不详细讲解了
- 配置数据源的时候name要注意,class引用路径不要引用错误,都要根据实际情况修改;
- sql:sqlmaps/sqlMap_*.xml;意思就是放在sqlmaps目录下以sqlMap_*.xml格式命名。
- 启动没有报错,就可以利用封装对数据库进行一下操作测试是否成功。
- String sqlId = NAME_SPACE+"自定义命名"。
- 相关配置按照实际情况修改