JDBC中DAO层设计与实现

JDBC(全称:Java Data Base Connectivity)是java数据库连接简称 ,提供连接各种数据库的能力。

JDBC API主要的功能

1.与数据库建立连接;

2.执行SQL语句;

3.处理结果。

JDBC关键字的使用

1.DriverManager:依据数据库的不同,管理JDBC驱动;

2.Connection:负责连接数据库并且担任传送数据库的任务;

3.Statement:由Connection产生、负责执行SQL语句;

4.ResultSet:负责保存Statement执行后所产生的查询结果;

5.PreparedStatement接口(预编译的SQL语句)提高了SQL语句的性能、代码的安全性、代码的可读性和可维护性。

 

Statement常用方法:

ResultSet executeQuery(String sql):执行SQL查询并且获取ResultSet对象

Int executeUpdate(String sql):可以执行插入、删除、更新等操作,返回值是执行该操作所影响的行数

Boolean execute(String sql):可以执行任意SQL语句,然后获得一个布尔值,表示是否返回ResultSet

Boolean next():将光标从当前位置向下移动一行

Boolean previous():游标从当前位置向上移动一行

Void close():关闭ResultSet对象

Int getInt(int colIndex):以int形式获取结果集当前行指定列号值

Int getInt(String colLabel):以int形式获取结果集当前行指定的列名值

Float getFloat(int colIndex):以float形式获取结果集当前行指定列号值

Float getFloat(String colLabel):以float形式获取结果集当前指定列名值

String getString(int colIndex):以Sting形式获取当前行指定列号值

String getString(String colLabel):以String形式获取当前行指定列名值

PreparedStatement比Statement提高了代码的可读性和可维护性,提高了SQL语句执行的性能,提高了安全性。

JDBC的操作步骤

1.加载JDBC驱动;

2.与数据库建立连接;

3.创建Statement或PreparedStatement对象;

4.发送SQL语句,并且得到返回结果;

5.处理返回结果;

6.释放资源。

遍历结果集中数据可使用列号或者列名标识列。

数据访问层 - DAO模式

持久化是将程序中的数据在瞬时状态下和持久状态间转换的机制。

持久化的主要操作:读取、查找、保存、修改、删除。

DAO(Data Access Object):数据存取对象,位于业务逻辑和持久化数据之间,能够实现对持久化数据的访问。

DAO在实体类与数据库之间起着转换器的作用,能够把实体类转换为数据库中的记录。


DAO模式是作用

1.隔离业务逻辑代码和数据访问代码;

2.隔离不同数据库的实现。


DAO模式的组成部分

1.DAO接口;

2.DAO实现类;

3.实体类;

4.数据库连接和关闭工具类。

分层开发

一种化大为小,分而治之的软件开发方法。

分层的特点:

1.每一层都有自己的职责;

2.上层不用关心下次的实现细节,上层通过下层提供的对外接口来使用其功能;

3.上一层调用下一层的功能,下一层不能调用上一层的功能。


分层开发的好处:

1.各层专注于自己功能的实现,便于提高质量;

2.便于分工协作,提高开发效率;

3.便于代码复用;

4.便于程序扩展。


分层原则:

1.封装性原则:每个层次向外公开接口,但是隐藏内部细节

2.顺序访问原则:下一层为上一层服务,但不使用上层的服务

分层结构中,不同层之间通过实体类传输数据。
 
根据分层开发DAO模式创建步骤
1:建立数据库,建表;
2:创建实体类,和相应的数据库的表是对应的;
3:创建Dao的基类接口类;
4:创建Dao的通用实现类;
5:创建具体表的Dao类;
6:创建具体表的Dao实现类;
7 : 创建业务逻辑层的接口类;
8:创建业务逻辑层的接口实现类;
9 : 创建测试类。


第一步:建库建表:略

第二步:创建实体类

package com.jdbcLean;
import java.io.Serializable;
import java.sql.Blob;
import java.sql.Date;

public class User implements Serializable {
    private static final long serialVersionUID = 4131873907877763625L;
    private int id;
    private String userName;
    private String password;
    private Date date;
    private String address;   
    private Blob picture;
    public User(){}

   public User(int id, String userName, String password, Date date, String address, Blob picture) {
        this.id = id;
        this.userName = userName;
        this.password = password;
        this.date = date;
        this.address = address;
        this.picture = picture;
    }
	
   public User(int id, String userName, String password, Date date, String address) {
        this.id = id;
        this.userName = userName;
        this.password = password;
        this.date = date;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {

        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }


    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Blob getPicture() {
    	return picture;
    }
    
    public void setPicture(Blob picture) {
    	this.picture = picture;
    }
    
    @Override
    public String toString() {
        return "User{" + "userId=" + id + ", userName='" + userName + '\'' + ", password='" + password + '\'' +
                ", date=" + date + ", address='" + address + '\'' + '}';
    }
}

第三步:创建Dao的基类接口

package com.jdbcLean;

import java.sql.Connection;
import java.util.List;
import java.sql.SQLException;

/**
 * 访问数据库的Dao接口。
 * 其中定义了访问数据库的方法:DELETE,UPDATE,QUERY,INSERT,BATCH
 */
public interface Dao<T> {
    /**
     * INSERT,UPDATE,DELETE
     * @param sql:SQL语句
     * @param connection:数据库连接
     * @param args:填充占位符的可变参数
     */
    int update(Connection connection, String sql, Object... args) throws SQLException ;

    /**
     * INSERT,UPDATE,DELETE
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     */
    int update(String sql, Object... args) throws SQLException;

    /**
     * INSERT,UPDATE,DELETE
     * @param sql:SQL语句
     */
    int update(String sql) throws SQLException ;

    /**
     * INSERT,UPDATE,DELETE
     * @param sql:SQL语句
     * @param connection:数据库连接
     */
    int update(Connection connection, String sql) throws SQLException;

    /**
     * 返回一个 T 的对象
     * @param sql:SQL语句
     * @return
     */
    T queryObject(/*Class<T> clazz, */String sql) throws SQLException ;

    /**
     * 返回一个 T 的对象
     * @param sql:SQL语句
     * @return
     */
    T queryObject(/*Class<T> clazz, */Connection connection, String sql) throws SQLException ;

    /**
     * 返回一个 T 的对象
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     * @return
     */
    T queryObject(/*Class<T> clazz, */String sql, Object... args) throws SQLException ;

    /**
     * 返回一个 T 的对象
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     * @return
     */
    T queryObject(/*Class<T> clazz, */Connection connection, String sql, Object... args) throws SQLException ;

    /**
     * 返回 T 的一个集合
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     * @return
     */
    List<T> queryObjects(/*Class<T> clazz, */Connection connection, String sql, Object... args) throws SQLException ;

    /**
     * 返回一个具体的值
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     * @return
     */
    <E> E getValue(Connection connection, String sql, Object... args) throws SQLException;

    /**
     * 批量处理方法
     * @param sql:SQL语句
     * @param args:填充占位符的Object[]类型的可变参数
     * @return
     */
    void batch(Connection connection, String sql, Object[]... args) throws SQLException;
}

第四步:创建Dao的通用实现类

package com.jdbcLean;

import java.lang.reflect.ParameterizedType;
import com.jdbcLean.Dao;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import javax.sql.DataSource;
import java.sql.*;
import java.util.List;

/**
 * 能否解决高并发读写操作问题?
 * 
 * 如何利用工厂模式使用Dao?
 * 
 * ThreadLocal管理conn进行事务处理的案例:https://blog.csdn.net/weisubao/article/details/52575787
 * QueryRunner(DataSource ds)构造方法的实际用处:https://www.oschina.net/question/273800_55356
 * 利用反射搭建项目的dao层:http://www.mamicode.com/info-detail-1552193.html
 * JDBC中Dao层:https://blog.csdn.net/whycmpx/article/details/78901875
 * 关于JDBC和DAO模式使用:https://www.cnblogs.com/qi-dian/p/6185545.html
 * @param <T> : 子类需传入的泛型类型.
 */
public class JdbcDaoImpl<T> implements Dao<T>{
    //QueryRunner是线程安全的
    private QueryRunner queryRunner = null;

    private Class<T> type;

    protected DataSource dataSource;

    public JdbcDaoImpl(){
        this.dataSource = null;
        this.init();
    }

    public JdbcDaoImpl(DataSource dataSource){
        this.dataSource = dataSource;
        this.init();
    }

    @SuppressWarnings("unchecked")
	protected void init(){
        this.queryRunner = new QueryRunner();
        // 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
   	    // 如: CustomerDao extends JdbcDaoImpl<User>
        type = (Class <T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    protected Connection prepareConnection() throws SQLException {
        if (this.getDataSource() == null) {
            throw new SQLException("dataSource is null.");
        } else {
            return this.getDataSource().getConnection();
        }
    }

    public DataSource getDataSource() {
        return this.dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public int update(String sql) throws SQLException {
        Connection connection = this.prepareConnection();
        return this.update(connection, sql, (Object[])null);

    }

    @Override
    public int update(Connection connection, String sql) throws SQLException {
        return this.update(connection, sql, (Object[])null);
    }

    @Override
    public int update(String sql, Object... args) throws SQLException {
        Connection connection = this.prepareConnection();
        return this.update(connection, sql, args);
    }

    /**
     * UPDATE,INSERT,DELETE
     * @param connection:数据库连接
     * @param sql:SQL语句
     * @param args:填充占位符的可变参数
     * @return
     * @throws SQLException
     */
    @Override
    public int update(Connection connection, String sql, Object... args) throws SQLException {
        if (connection == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            this.closeConnection(connection);
            throw new SQLException("Null SQL statement");
        }
        int rows = 0;
        try{
            //事物开始
            rows = queryRunner.update(connection,sql,args);
            //事物提交
        }catch(Exception e){
            //发生异常,事物回滚
            e.printStackTrace();
        } finally {
            this.closeConnection(connection);
        }
        return rows;
    }

    @Override
    public T queryObject(/*Class<T> clazz, */String sql) throws SQLException {
        Connection connection = this.prepareConnection();
        return this.queryObject(/*clazz,*/connection,sql,(Object[]) null);
    }

    @Override
    public T queryObject(/*Class<T> clazz, */Connection connection, String sql) throws SQLException {
        return this.queryObject(/*clazz,*/connection,sql,(Object[]) null);
    }

    @Override
    public T queryObject(/*Class<T> clazz, */String sql, Object... args) throws SQLException {
        Connection connection = this.prepareConnection();
        return this.queryObject(/*clazz,*/connection,sql,args);
    }

    @Override
    public T queryObject(/*Class<T> clazz, */Connection connection, String sql, Object... args) throws SQLException {
        if (connection == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            this.closeConnection(connection);
            throw new SQLException("Null SQL statement");
        }
        T entity = null;
        try {
        	//可以通过反射, 获得 Class 定义中声明的父类的泛型参数类型, 因此就不再需要传入Class类型了.
            ResultSetHandler<T> rsh = new BeanHandler<T>(/*clazz*/type);
            boolean flag = args == null ? true : false;
            if (flag){
                entity = queryRunner.query(connection,sql,rsh);
            } else {
                entity = queryRunner.query(connection,sql,rsh,args);
            }
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            this.closeConnection(connection);
        }
        return entity;
    }

    @Override
    public List<T> queryObjects(/*Class<T> clazz, */Connection connection, String sql, Object... args) throws SQLException {
        if (connection == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            this.closeConnection(connection);
            throw new SQLException("Null SQL statement");
        }
        List<T> resultList = null;//new ArrayList<>();
        try {
            ResultSetHandler<List<T>> rsh = new BeanListHandler<T>(/*clazz*/type);
            boolean flag = args == null ? true : false;
            if (flag){
                resultList = queryRunner.query(connection,sql,rsh);
            } else {
                resultList = queryRunner.query(connection,sql,rsh,args);
            }
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            this.closeConnection(connection);
        }
        return resultList;
    }

    @Override
    public <E> E getValue(Connection connection, String sql, Object... args) throws SQLException {
        if (connection == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            this.closeConnection(connection);
            throw new SQLException("Null SQL statement");
        }

        E value = null;
        try {
            //第一行的第一列
            ResultSetHandler<E> rsh = new ScalarHandler<E>();
            value = queryRunner.query(connection,sql,rsh,args);
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            this.closeConnection(connection);
        }
        return value;
    }

    @Override
    public void batch(Connection connection, String sql, Object[]... args) throws SQLException {
    	if (connection == null) {
            throw new SQLException("Null connection");
        } else if (sql == null) {
            this.closeConnection(connection);
            throw new SQLException("Null SQL statement");
        }
    	queryRunner.batch(connection, sql, args);
    }

    public void closeConnection(Connection connection) throws SQLException {
        if (null != connection){
            connection.close();
        }
    }
}

通过返回获取获得定义 Class 时声明的父类的泛型参数的类型:

	/**
	 * 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
	 * 如: public EmployeeDao extends BaseDao<Employee, String>
	 * @param clazz
	 * @param index
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Class getSuperClassGenricType(Class clazz, int index){
		Type genType = clazz.getGenericSuperclass();
		
		if(!(genType instanceof ParameterizedType)){
			return Object.class;
		}
		
		Type [] params = ((ParameterizedType)genType).getActualTypeArguments();
		
		if(index >= params.length || index < 0){
			return Object.class;
		}
		
		if(!(params[index] instanceof Class)){
			return Object.class;
		}
		
		return (Class) params[index];
	}

第五步:创建具体表的Dao类和实现类(省去了接口类)

package com.jdbcLean;

public class CustomerDao extends JdbcDaoImpl<User> {
    public CustomerDao(){
        super();
    }

    public User getUser() throws Exception {
        String selectSql = "SELECT * FROM userinfos WHERE userName = ?";
        return super.queryObject(JdbcUtils.getConnection(),selectSql,"aerfa");
    }

    public int update() throws Exception {
        String updateSql = "UPDATE userinfos SET userName='Tom',password='admin123' WHERE id=?";
        return super.update(JdbcUtils.getConnection(),updateSql,19);
    }

    public int insert() throws Exception {
        String insertSql = "INSERT INTO userinfos(userName,password,address) VALUES(?,?,?)";
        return super.update(JdbcUtils.getConnection(),insertSql,"hq","heqiang123","chengdu");
    }

    public int delete() throws Exception {
        String deleteSql = "DELETE FROM userinfos WHERE id = ?";
        return super.update(JdbcUtils.getConnection(),deleteSql,21);
    }

    public Object getValue() throws Exception {
        String getSql = "SELECT password FROM userinfos WHERE userName = ?";
        return super.getValue(JdbcUtils.getConnection(),getSql,"Tom");
    }

}

第六步:创建业务逻辑层的接口类和实现类(省去了接口类)

package com.jdbcLean;

public class UserServer {

}

第七步:创建测试类

package com.jdbcLean;

public class DbutilsImplDaoTest {

	public static void main(String[] args) throws Exception {
		CustomerDao dao = new CustomerDao();

        System.out.println(dao.getUser());

        System.out.println(dao.update());

        System.out.println(dao.insert());

        System.out.println(dao.delete());

        System.out.println(dao.getValue());
	}

}


数据库连接 与 数据库事物

//后面更新... ...

参考内容:

关于JDBC和DAO模式使用

猜你喜欢

转载自blog.csdn.net/jingzi123456789/article/details/80659158