Java基于jdbctemplate数据持久层操作封装

相关资源分享-下载可直接使用:

https://download.csdn.net/download/csdn_heliu/10736181

JdbcTemplate简介:

  1. spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中。
  2. JdbcTemplate主要提供以下五类方法:
  • execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
  • update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
  • query方法及queryForXXX方法:用于执行查询相关语句;
  • call方法:用于执行存储过程、函数相关语句。

为啥要使用JdbcTemplate进行开发呢?

  1. Spring提供的JdbcTemplate对jdbc做了封装,大大简化了数据库的操作。
  2. 如果直接使用JDBC的话,需要我们加载数据库驱动、创建连接、释放连接、异常处理等一系列的动作,繁琐且代码看起来不直观。
  3. 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"> &lt;!&ndash; PropertyPlaceholderConfigurer类中有个locations属性,接收的是一个数组,即我们可以在下面配好多个properties文件 &ndash;&gt;
                <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>

 注意:

  1. 需要的jar依赖,根据需求导入,这里就不详细讲解了
  2. 配置数据源的时候name要注意,class引用路径不要引用错误,都要根据实际情况修改;
  3. sql:sqlmaps/sqlMap_*.xml;意思就是放在sqlmaps目录下以sqlMap_*.xml格式命名。
  4. 启动没有报错,就可以利用封装对数据库进行一下操作测试是否成功。
  5. String sqlId = NAME_SPACE+"自定义命名"。
  6. 相关配置按照实际情况修改

猜你喜欢

转载自blog.csdn.net/CSDN_HELIU/article/details/83272808