编写自己的JDBC框架

作者: 小小蒜头 | 来源:发表于2017-10-02 23:35 被阅读60次

我们知道如何通过JDBC连接并操作数据库,但是每次我们实现增删改查时都会有一大段重复代码,所以本文主要是用实例说明了如何优化那些代码。这只是初步的简单优化。后面我会持续更新的。

你要是忍不急想看主要代码,前往第5步工具类。

1. 建表account

create table account(
    id int primary key auto_increment,
    name varchar(40),
    money float
);character set utf8 collate utf8_general_ci;

insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);

2. 连接数据库的配置文件

在这个阶段的学习里,此配置文件可以当做模板来使用,并且里面有很详细的注释。

dbcpConfig.properties

#连接设置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testbatch
username=root
password=root

#初始化连接
initialSize=10

#最大连接数量
maxActive=50

#<!-- 最大空闲连接 -->
maxIdle=20

#<!-- 最小空闲连接 -->
minIdle=5

#<!-- 超时等待时间以毫秒为单位  6000毫秒/1000=60秒 -->
maxWait=60000

#JDBC驱动建立连接时附带的连接属性的格式必须为这样:[属性名=property;]
#注意:"user"与"password"两个属性会被明确传递,因此这里不需要包含它们
connectionProperties=useUnicode=true;characterEncoding=utf8

#指定由连接池所创建的连接的自动提交(auto-commit)状态
defaultAutoCommit=true

#如果没有设置该值,则"setReadOnly"方法将不被调用。(某些驱动并不支持只读模式,如:Infomix)
defaultReadOnly

#driver default 指定由连接池所创建连接的事务级别(TransactionIsolation)
#可用值:NONE,READ_UNCOMMITTED,READ_COMMITTED,REPEATABLE_READ,SERIALIZABLE
defalutTransactionIsolation=READ_COMMITTED

3. 连接池JdbcUtils_DBCP

package cn.itcast.utils;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * Created by yvettee on 2017/9/30.
 */
public class JdbcUtils_DBCP {
    private static DataSource ds = null;

    static {
        try {
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpConfig.properties");
            Properties prop = new Properties();
            prop.load(in);

            BasicDataSourceFactory factory = new BasicDataSourceFactory();
            ds = factory.createDataSource(prop);
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    public static Connection getConnection() throws SQLException {
        return ds.getConnection();
    }

    public static void release(Connection conn, Statement st, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();   //throw new
            } catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (st != null) {
            try {
                st.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            st = null;
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

4. 实体类Account

package cn.itcast.domain;

/**
 * Created by yvettee on 2017/9/30.
 */
public class Account {
    private int id;
    private String name;
    private double money;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double price) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

5.工具类

JdbcUtils

这个类里面就主要是对增删改查代码的优化了。增删改比较简单,用update一个方法就可以解决,主要就是查询比较复杂。因为查询时根据查询语句的不同,返回的结果集就不一样,不知道怎么处理,但是用户知道。在做开发的过程中,拿到结果集了,不知道怎么处理,就向用户暴露一个接口,你实现接口我这边就调用接口处理。

package cn.itcast.utils;

import java.sql.*;

/**
 * Created by yvettee on 2017/9/30.
 */
public class JdbcUtils {

    //add update delete
    // sql="insert into account(id,name,money) values(?,?,?) Object[]{1,"a",100}"
    public static void update(String sql, Object params[]) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils_DBCP.getConnection();
            ps = conn.prepareStatement(sql);
            //Object params[]替换sql里面的参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils_DBCP.release(conn, ps, rs);
        }
    }

    //查找的优化是最难的
    public static Object query(String sql, Object params[], ResultSetHandler handler) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils_DBCP.getConnection();
            ps = conn.prepareStatement(sql);
            //Object params[]替换sql里面的参数
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            //不知道sql语句是怎样的,也就不知道怎么处理rs,但是用户知道怎么处理
            rs = ps.executeQuery();
            return handler.handler(rs);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils_DBCP.release(conn, ps, rs);
        }
        return null;
    }
}

ResultSetHandler接口

package cn.itcast.utils;

import java.sql.ResultSet;

/**
 * Created by yvettee on 2017/10/2.
 */
//暴露一个处理结果集的接口
public interface ResultSetHandler {
    //返回多个值,Object类型
    public Object handler(ResultSet rs);
}

BeanHandlerImpl对接口进行处理

package cn.itcast.utils;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;

/**
 * Created by yvettee on 2017/10/2.
 */
public class BeanHandlerImpl implements ResultSetHandler {
    private Class clazz;

    public BeanHandlerImpl(Class clazz) {
        this.clazz = clazz;
    }

    @Override
    public Object handler(ResultSet rs) {
        try {
            if (!rs.next()) {
                return null;
            }

            //创建出封装结果集的bean
            Object bean = clazz.newInstance();
            //得到结果集的元数据,以获取结果集的信息
            ResultSetMetaData meta = rs.getMetaData();
            int count = meta.getColumnCount();
            for (int i = 0; i < count; i++) {
                String name = meta.getColumnName(i + 1);//获取到结果集每列的列名
                Object value = rs.getObject(name);
                //将获取到的值封装到与bean上相对应的属性上去(反射出bean上与列名相应的属性)
                Field f = bean.getClass().getDeclaredField(name);
                f.setAccessible(true);
                f.set(bean, value);
            }
            return bean;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

6. 接口以及接口的实现

AccountDao

package cn.itcast.dao.impl;

import cn.itcast.domain.Account;

/**
 * Created by yvettee on 2017/10/1.
 */
public interface AccountDao {
    void add(Account account);

    void delete(int id);

    void update(Account account);

    Account find(int id);
}

AccountDaoImpl

package cn.itcast.dao.impl;

import cn.itcast.domain.Account;
import cn.itcast.utils.BeanHandlerImpl;
import cn.itcast.utils.JdbcUtils;

/**
 * Created by yvettee on 2017/9/30.
 */
public class AccountDaoImpl implements AccountDao {

    @Override
    public void add(Account account) {
        String sql = "insert into account(name,money) values(?,?)";
        Object params[] = {account.getName(), account.getMoney()};
        JdbcUtils.update(sql, params);
    }

    @Override
    public void delete(int id) {
        String sql = "delete from account where id=?";
        Object params[] = {id};
        JdbcUtils.update(sql, params);
    }

    @Override
    public void update(Account account) {
        String sql = "update account set name=?,money=? where id=?";
        Object params[] = {account.getName(), account.getMoney(), account.getId()};
        JdbcUtils.update(sql, params);
    }

    @Override
    public Account find(int id) {
        String sql = "select * from account where id=?";
        Object params[] = {id};
        return (Account)JdbcUtils.query(sql,params,new BeanHandlerImpl(Account.class));
    }
}

7. Junit测试

package cn.itcast.test;

import cn.itcast.dao.impl.AccountDao;
import cn.itcast.dao.impl.AccountDaoImpl;
import cn.itcast.domain.Account;
import org.junit.Test;

/**
 * Created by yvettee on 2017/10/1.
 */
public class TestAccount {
    @Test
    public void testAdd() {
        Account a = new Account();
        a.setName("车村");
        a.setMoney(100.23);
        AccountDao dao = new AccountDaoImpl();
        dao.add(a);
        System.out.println(a);
    }

    @Test
    public void testDelete() {
        AccountDao dao = new AccountDaoImpl();
        dao.delete(10);
    }

    @Test
    public void testUpdate() {
        Account a = new Account();
        a.setName("车村");
        a.setMoney(100.23);
        a.setId(1);
        AccountDao dao = new AccountDaoImpl();
        dao.update(a);
    }

    @Test
    public void testQuery() {
        AccountDao dao = new AccountDaoImpl();
        dao.find(1);
        System.out.println(dao.find(1));
    }

}

本文的源代码:https://github.com/yvettee36/JdbcFrame

对之前写的客户关系管理案例里面的代码进行小小的优化。源代码
上篇:编写自己的JDBC框架之元数据

相关文章

  • 编写自己的JDBC框架

    我们知道如何通过JDBC连接并操作数据库,但是每次我们实现增删改查时都会有一大段重复代码,所以本文主要是用实例说明...

  • MyBatis的发展和选型

    数据层框架的发展史 JDBC编码的几大问题和MyBatis等框架的发展支持原因?在最初编写JDBC连接数据库的时候...

  • 编写自己的JDBC框架之元数据

    编写自己的JDBC框架所涉及到的几个知识点先了解一下。元数据:拿到元数据,就相当于拿到了数据库的定义信息。 元数据...

  • 阿里技术官十年经验,写出的Mybatis笔记,完整版免费下载

    前言: Mybatis是一款优秀的持久层框架。其封装了JDBC操作, 免去了开发人员编写JDBC 代码以及设置参数...

  • ssh框架的基本整合

    Spring框架的基本整合 AOP注解方式编写切面类(包含通知和切入点)开启自动代理 JDBC模板技术Spring...

  • Spring-整合MyBatis

    零、本文纲要 一、JDBC & MyBatis相关内容 JDBC-手动编写SQL MyBatis-手动编写SQL ...

  • ① 编写jdbc的工程代码用于分析程序的耦合

    通过编写JDBC的工程代码来分析程序的耦合首先创建Maven工程,加入mysql的依赖,编写JDBC程序. ④创建...

  • 02. 程序的耦合

    通过编写JDBC的工程代码来分析程序的耦合 首先创建Maven工程,加入mysql的依赖,编写JDBC程序. ④创...

  • Spring整合MyBatis

    MyBatis是一个半自动的ORM框架,它要求开发者编写具体的SQL语句。MyBatis解决的问题:JDBC使用复...

  • Mybatis

    什么是mybatis mybatis是一款优秀的持久层框架,他几乎可以让我们避免JDBC的编写已经对结果集的映射,...

网友评论

    本文标题:编写自己的JDBC框架

    本文链接:https://www.haomeiwen.com/subject/ieegextx.html