• 轻量级封装DbUtils&Mybatis之二Dbutils


    DbUtils入门#

    Apache出品的极为轻量级的Jdbc访问框架,核心类只有两个:QueryRunner和ResultSetHandler。
    各类ResultSetHandler:
    ArrayHandler:把结果集中的第一行数据转成对象数组。
    ArrayListHandler:把结果集中的每一行数据都转成一个数组,再存放到List中。
    BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。

    请参考孤傲苍狼的博客javaweb学习总结(四十一)——Apache的DBUtils框架学习,墙裂推荐。

    Detail#

    测试样例代码##

    package org.wit.ff.jdbc;
    
    
    import org.junit.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
    import org.wit.ff.jdbc.access.IDataAccessor;
    import org.wit.ff.jdbc.converter.ParamsConverter;
    import org.wit.ff.jdbc.sql.db.MySQLBuilder;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * Created by F.Fang on 2015/3/31.
     * Version :2015/3/31
     */
    @ContextConfiguration(locations = {"classpath:applicationContext.xml"})
    public class CRUDTest extends AbstractJUnit4SpringContextTests{
    
        @Autowired
        private IDataAccessor dataAccessor;
    
        @Test
        public void query(){
            MySQLBuilder builder = new MySQLBuilder();
            // sql: select * from Audience limit 2
            builder.SELECT("*").FROM("Audience").PAGE(0, 2);
            String sql = builder.toString();
            final Audience audience = new Audience();
            audience.setName("ff");
    
            // 也可以直接填写SQL.
            List<Audience> list = dataAccessor.query(sql, null, Audience.class);
            System.out.println(list);
        }
    
        @Test
        public void insert(){
            // 批量新增.
            String sql = "insert into audience(id,name,pay) values(?,?,?)";
            Object[][] params = new Object[1][];
            params[0] = new Object[]{100,"ff",100.1};
            dataAccessor.insert(sql, params);
        }
    
        @Test
        public void insertDate(){
            // 试试日期.
            String sql = "insert into test_date(id,current) values(?,?)";
            Object[][] params = new Object[1][];
            params[0] = new Object[]{100, new Date()};
            dataAccessor.insert(sql, params);
        }
    
        @Test
        public void insertWithParamsConverter(){
            // 试试PramsConverter好用不.
            ParamsConverter<Audience> converter = new ParamsConverter<Audience>() {
                @Override
                public Object[] convert(Audience audience) {
                    return new Object[]{audience.getId(), audience.getName(), audience.getPay()};
                }
            };
    
            String sql = "insert into audience(id,name,pay) values(?,?,?)";
            // 构造数据.
            List<Audience> list = new ArrayList<>();
            Audience audience1 = new Audience();
            audience1.setId(250);
            audience1.setName("ff");
            audience1.setPay(1000.00);
    
            Audience audience2 = new Audience();
            audience2.setId(251);
            audience2.setName("ff1");
            audience2.setPay(1000.00);
    
            list.add(audience1);
            list.add(audience2);
    
            dataAccessor.insert(sql, list, Audience.class, converter);
            
        }
    
    }
    
    

    Audience

    package org.wit.ff.jdbc;
    
    import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
    import org.apache.commons.lang3.builder.ToStringStyle;
    
    /**
     * Created by F.Fang on 2015/2/16.
     * Version :2015/2/16
     */
    public class Audience {
        private Integer id;
    
        private String name;
    
        private Double pay;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Double getPay() {
            return pay;
        }
    
        public void setPay(Double pay) {
            this.pay = pay;
        }
    
        @Override
        public String toString() {
            return ReflectionToStringBuilder.toString(this, ToStringStyle.SIMPLE_STYLE);
        }
    }
    

    配置

    <!-- 数据库连接池 -->
        <bean id="dataSource"
              class="org.apache.commons.dbcp.BasicDataSource"
              destroy-method="close">
            <property name="driverClassName" value="${db.driverClass}"/>
            <property name="url" value="${db.jdbcUrl}"/>
            <property name="username" value="${db.user}"/>
            <property name="password" value="${db.password}"/>
        </bean>
    
        <bean id="dataAccessor" class="org.wit.ff.jdbc.access.dbutils.DefaultDataAccessor">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    

    备注:实际数据源配置还是需要优化的

    看上去还凑合,调用比较简单,那么接下来看看具体的实现吧!

    AbstractDataAccessor##

    • QueryRunner无参构造对象
    • 抽象获取连接和关闭连接的方法
    package org.wit.ff.jdbc.access.dbutils;
    
    import org.apache.commons.dbutils.QueryRunner;
    import org.apache.commons.dbutils.handlers.*;
    import org.apache.commons.lang3.StringUtils;
    import org.wit.ff.jdbc.converter.ParamsConverter;
    import org.wit.ff.jdbc.access.IDataAccessor;
    import org.wit.ff.jdbc.exception.DbUtilsDataAccessException;
    import org.wit.ff.jdbc.id.IdGenerator;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.util.List;
    
    /**
     * Created by F.Fang on 2015/3/31.
     * Version :2015/3/31
     */
    public abstract class AbstractDataAccessor implements IDataAccessor {
    
        /**
         * 获取连接的方法时抽象的,目的是为了和事务绑定,开放Connection来源.
         * @return
         * @throws SQLException
         */
        protected abstract Connection getConnection() throws SQLException;
    
        /**
         * 获取连接的方法时抽象的,目的是为了和事务绑定,因为事务执行前后包含的sql逻辑可能不只一条, 不可在一条sql执行逻辑完成后关闭.
         * @param conn
         */
        protected abstract void closeConn(Connection conn);
    
        @Override
        public <T> List<T> query(String sql, Class<T> resultType){
            return query(sql, null, resultType);
        }
    
        /**
         * 查询时BeanListHandler将结果集转换成对象列表.
         * @param sql 查询语句
         * @param params 查询参数
         * @param resultType 返回类型
         * @param <T>
         * @return
         */
        @Override
        public <T> List<T> query(String sql, Object[] params, Class<T> resultType) {
            if (resultType == null || StringUtils.isBlank(sql)) {
                throw new DbUtilsDataAccessException("resultType can't be null and sql can't be blank!");
            }
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            List<T> result = null;
            try {
                conn = getConnection();
                if (params != null) {
                    result = (List<T>) runner.query(conn, sql, new BeanListHandler(resultType), params);
                } else {
                    result = (List<T>) runner.query(conn, sql, new BeanListHandler(resultType));
                }
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("query error, sql is:" + sql, e);
            } finally {
                closeConn(conn);
            }
            return result;
        }
    
        /**
         *
         * @param sql insert语句.
         * @param params 对象参数列表.
         * @param paramsType 参数类型.
         * @param converter 参数转换器.
         * @param <T>
         */
        @Override
        public <T> void insert(String sql, List<T> params, Class<T> paramsType, ParamsConverter<T> converter) {
            if (StringUtils.isBlank(sql)) {
                throw new DbUtilsDataAccessException("sql can't be blank!");
            }
            if (params == null || params.isEmpty()) {
                throw new DbUtilsDataAccessException("params can't be null or empty!");
            }
            if (paramsType == null || converter == null) {
                throw new DbUtilsDataAccessException("paramsType or converter can't be null!");
            }
    
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            ArrayListHandler handler = new ArrayListHandler();
            List<Object[]> keys = null;
            try {
                conn = getConnection();
                int len = params.size();
                Object[][] arr = new Object[len][];
                for (int i = 0; i < len; ++i) {
                    // 将单个对象处理成单行记录,用数组表示.
                    arr[i] = converter.convert(params.get(i));
                }
                // 获取主键.
                keys = (List<Object[]>) runner.insertBatch(conn, sql, handler, arr);
                if (keys != null && keys.size() == len) {
                    // implements IdGenerator.
                    // 如果当前对象实现了IdGenerator接口, 则执行主键赋值的逻辑, 赋值逻辑由用户自定义在具体的对象类型当中
                    if (params.get(0) instanceof IdGenerator) {
                        for (int i = 0; i < len; ++i) {
                            // 对每一个对象执行主键赋值(解析)
                            ((IdGenerator) params.get(i)).parseGenKey(keys.get(i));
                        }
                    }
                }
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("batch insert error, sql is:" + sql, e);
            }finally {
                closeConn(conn);
            }
        }
    
        /**
         * 批量插入.
         * @param sql
         * @param params
         */
        @Override
        public void insert(String sql, Object[][] params) {
            if(params==null || StringUtils.isBlank(sql)){
                throw new DbUtilsDataAccessException("params can't be null and sql can't be empty!");
            }
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            ArrayListHandler handler = new ArrayListHandler();
            try {
                conn = getConnection();
                runner.insertBatch(conn, sql, handler, params);
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("batch insert error, sql is:" + sql, e);
            }finally {
                closeConn(conn);
            }
        }
    
        /**
         * 单条插入.
         * @param sql
         * @param params
         */
        @Override
        public void insert(String sql, Object[] params) {
            if(params==null || StringUtils.isBlank(sql)){
                throw new DbUtilsDataAccessException("params can't be null and sql can't be empty!");
            }
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            ArrayHandler handler = new ArrayHandler();
            try {
                conn = getConnection();
                runner.insert(conn, sql, handler, params);
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("insert error, sql is:" + sql, e);
            }finally {
                closeConn(conn);
            }
        }
    
        /**
         * 批量更新.
         * @param sql
         * @param params
         * @return
         */
        @Override
        public int[] update(String sql, Object[][] params) {
            if(params==null || StringUtils.isBlank(sql)){
                throw new DbUtilsDataAccessException("params can't be null and sql can't be empty!");
            }
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            int[] result = null;
            try {
                conn = getConnection();
                result = runner.batch(conn, sql, params);
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("batch update error, sql is:" + sql, e);
            }finally {
                closeConn(conn);
            }
            return result;
        }
    
        /**
         * 单条更新.
         * @param sql
         * @param params
         * @return
         */
        @Override
        public int update(String sql, Object[] params) {
            QueryRunner runner = new QueryRunner();
            Connection conn = null;
            int result = 0;
            try {
                conn = getConnection();
                if (params != null) {
                    result = runner.update(conn, sql, params);
                } else {
                    result = runner.update(conn, sql);
                }
            } catch (Exception e) {
                throw new DbUtilsDataAccessException("update error, sql is:" + sql, e);
            }finally {
                closeConn(conn);
            }
            return result;
        }
    
        /**
         * 删除,没有必要批量.
         * 即使是批量,也可以调用批量更新的方法.
         * 事实上此方法并无太大必要,只是为了避免歧义而已.
         * @param sql
         * @param params
         * @return
         */
        @Override
        public int delete(String sql, Object[] params) {
            return update(sql, params);
        }
    
    }
    
    

    DefaultDataAccessor##

    package org.wit.ff.jdbc.access.dbutils;
    
    import org.apache.commons.dbutils.DbUtils;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    /**
     * Created by F.Fang on 2015/3/31.
     * 默认以配置数据源的方式获取连接.
     * Version :2015/3/31
     */
    public class DefaultDataAccessor extends AbstractDataAccessor {
    
        private DataSource dataSource;
    
        protected Connection getConnection() throws SQLException{
            return dataSource.getConnection();
        }
    
        @Override
        protected void closeConn(Connection conn) {
            try {
                DbUtils.close(conn);
            } catch (SQLException e) {
                // do nothing!
            }
        }
    
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    }
    

    DefaultTransactionDataAccessor##

    package org.wit.ff.jdbc.access.dbutils;
    
    import org.springframework.jdbc.datasource.DataSourceUtils;
    
    import javax.sql.DataSource;
    import java.sql.Connection;
    import java.sql.SQLException;
    
    /**
     * Created by F.Fang on 2015/4/23.
     * Version :2015/4/23
     */
    public class DefaultTransactionDataAccessor extends AbstractDataAccessor {
    
        private DataSource dataSource;
    
        protected Connection getConnection() throws SQLException {
    
            return DataSourceUtils.getConnection(dataSource);
            // 虽然可以将连接绑定到事务,但是当外部循dataAccessor的方法时,循环调用时会产生多个连接.
            //return DataSourceUtils.getConnection(dataSource);
            // 以下写法无法解决事务问题,无法将连接绑定到Spring 事务.
            // return dataSource.getConnection();
        }
    
        @Override
        protected void closeConn(Connection conn) {
            // do nothing!
        }
    
        public void setDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    }
    

    采用Spring事务集成方案,将Connection交给Spring管理,实际上Spring将Connection绑定到当前执行线程当中(以ConnectionHolder包装Connection,ThreadLocal包装ConnectionHolder绑定线程)
    详情参考DataSourceTransactionMananger的源代码,最好在doBeign和doCleanupAfterCompletion执行断点调试

    备注:AbstractDataAccessor开放getConnection()和closeConnection方法的原因也是调用过程Connection的开启和关闭不能由自身维持,否则会导致事务处理时Spring持有的Connection和AbstractDataAccessor执行方法的Connection不一致或在执行时拿到了关闭了的Connection对象

    QA#

  • 相关阅读:
    ecshop /includes/lib_base.php、/includes/fckeditor/editor/dialog/fck_spellerpages/spellerpages/server-scripts/spellchecker.php Backdoor Vul
    ecshop /pick_out.php SQL Injection Vul By Local Variable Overriding
    dedecms /include/filter.inc.php Local Variable Overriding
    dedecms plusguestbook.php SQL Injection Vul By plusguestbookedit.inc.php
    帝国备份王(Empirebak) classfunctions.php、classcombakfun.php GETSHELL vul
    dedecms /member/uploads_edit.php SQL Injection Vul
    PHP Lex Engine Sourcecode Analysis(undone)
    dedecms /member/resetpassword.php SQL Injection Vul
    dedecms /member/reg_new.php SQL Injection Vul
    dedecms /member/pm.php SQL Injection Vul
  • 原文地址:https://www.cnblogs.com/fangfan/p/4989312.html
Copyright © 2020-2023  润新知