Java基於jdbctemplate資料持久層操作封裝
阿新 • • 發佈:2018-11-10
相關資源分享-下載可直接使用:
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+"自定義命名"。
- 相關配置按照實際情況修改