JDBC DAO

前言:
JDBC是java访问数据库的基石,JDO, Hibernate等只是更好的封装了JDBC,
很多时候我们有必要了解jdbc怎么访问数据库;
介绍以下几个接口:
Java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现
                在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现
加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
DriverManager 类是驱动程序管理器类负责管理驱动程序,通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,
因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注
册自身的一个实例
Statement:通过调用 Connection 对象的 createStatement 方法创建该对象,该对象用于执行静态的 SQL 语句,并且返回执行结果
Statement 接口中定义了下列方法用于执行 SQL 语句:
ResultSet excuteQuery(String sql) ,int excuteUpdate(String sql)

PreparedStatement:可以通过调用 Connection 对象的 preparedStatement() 方法获取 PreparedStatement 对象
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement
对象的 setXXX() 方法来设置这些参数. setXXX() 方法有两个参数,第一个参数是要设置的 SQL 
语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值
PreparedStatement vs Statement:代码的可读性和可维护性. 
PreparedStatement 能最大可能提高性能:
DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句
在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预
编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行;
在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,
没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执
行一次都要对传入的语句编译一次;
(语法检查,语义检查,翻译成二进制命令,缓存)
PreparedStatement 可以防止 SQL 注入 

SQL 注入攻击:SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 
SQL 语句段或命令,从而利用系统的 SQL 引擎完成恶意行为的做法对于 Java 而言,要防范 SQL 注入,
只要用 PreparedStatement 取代 Statement 就可以了

ResultSet:  通过调用 Statement 对象的 excuteQuery() 方法创建该对象;
ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商实现
ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet
对象的 next() 方法移动到下一行

DatabaseMetaData:Java 通过JDBC获得连接以后,得到一个Connection 对象,可以从这个对象获得有关数据库管理
系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,触发器,存储过程等各方面
的信息。根据这些信息,JDBC可以访问一个实现事先并不了解的数据库。获取这些信息的方法都是
在DatabaseMetaData类的对象上实现的,而DataBaseMetaData对象是在Connection对象上获得的。
DatabaseMetaData 类中提供了许多方法用于获得数据源的各种信息,通过这些方法可以非常详细的
了解数据库的信息:
getURL():返回一个String类对象,代表数据库的URL。
getUserName():返回连接当前数据库管理系统的用户名。
isReadOnly():返回一个boolean值,指示数据库是否只允许读操作。
getDatabaseProductName():返回数据库的产品名称。
getDatabaseProductVersion():返回数据库的版本号。
getDriverName():返回驱动驱动程序的名称。

getDriverVersion():返回驱动程序的版本号。


案例:以下为基于JDBC DAO层的实现,代码精辟;

/*
 * 文件名:Dao.java
 * 版权:Copyright by www.huawei.com
 * 描述:
 * 修改人:Cuigaochong
 * 修改时间:2015-8-23
 * 跟踪单号:
 * 修改单号:
 * 修改内容:
 */

package com.jdbc.cgc.dao;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.beanutils.BeanUtils;

/**
 * <一句话功能简述>JDBC DAO精辟代码 <功能详细描述>
 * 
 * @author 姓名 工号
 * @version [版本号, 2015-8-23]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class Dao
{
    
    /**
     * <一句话功能简述>获取一个查询 项 <功能详细描述>
     * 
     * @param <E>
     * @param sql
     * @param args
     * @return
     * @see [类、类#方法、类#成员]
     */
    public <E> E getForValue(String sql, Object... args)
    {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        
        try
        {
            conn = getConn();
            preparedStatement = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++)
            {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            if (resultSet.next())
            {
                ResultSetMetaData rsmd = preparedStatement.getMetaData();
                String labelName = rsmd.getColumnLabel(1);
                return (E)resultSet.getObject(labelName);
            }
            
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            releaseSource(preparedStatement, conn, resultSet);
        }
        
        return null;
        
    }
    
    /**
     * <一句话功能简述>查询单条记录数据 <功能详细描述>
     * 
     * @param <T>
     * @param sql
     * @param clazz
     * @param args
     * @return
     * @see [类、类#方法、类#成员]
     */
    public <T> T getForSingle(String sql, Class<T> clazz, Object... args)
    {
        List<T> list = getForList(sql, clazz, args);
        if (0 < list.size())
        {
            return list.get(0);
        }
        return null;
    }
    
    /**
     * <一句话功能简述>查询多条记录数据 <功能详细描述>
     * 
     * @param <T>
     * @param sql
     * @param clazz
     * @param args
     * @return
     * @see [类、类#方法、类#成员]
     */
    public <T> List<T> getForList(String sql, Class<T> clazz, Object... args)
    {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<T> entryList = null;
        
        try
        {
            // 1:得到结果集
            conn = getConn();
            preparedStatement = conn.prepareStatement(sql);
            
            // 将参数放到preparedStatement的未知参数中
            for (int i = 0; i < args.length; i++)
            {
                preparedStatement.setObject(i + 1, args[i]);
            }
            
            resultSet = preparedStatement.executeQuery();
            // 2:处理结果集得到Map对应的List
            List<Map<String, Object>> list = handleResultSetoToMapList(resultSet);
            
            // 3:将List<Map<String,object>>转化成List<T>
            entryList = transfterMapListToBeanList(clazz, list);
            
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            releaseSource(preparedStatement, conn, resultSet);
        }
        
        return entryList;
    }
    
    /**
     * <一句话功能简述>数据库的增删改 <功能详细描述>
     * 
     * @param sql
     * @param args
     * @see [类、类#方法、类#成员]
     */
    public void update(String sql, Object... args)
    {
        Connection conn = null;
        PreparedStatement preparedStatement = null;
        ResultSet result = null;
        
        try
        {
            conn = getConn();
            preparedStatement = conn.prepareStatement(sql);
            
            // 将参数放到preparedStatement的未知参数中
            for (int i = 0; i < args.length; i++)
            {
                preparedStatement.setObject(i + 1, args[i]);
            }
            
            result = preparedStatement.executeQuery();
            
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            releaseSource(preparedStatement, conn, result);
        }
    }
    
    /**
     * <一句话功能简述>将MapList转化成BeanList <功能详细描述>
     * 
     * @param <T>
     * @param clazz
     * @param list
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @see [类、类#方法、类#成员]
     */
    private <T> List<T> transfterMapListToBeanList(Class<T> clazz, List<Map<String, Object>> list)
        throws InstantiationException, IllegalAccessException, InvocationTargetException
    {
        List<T> entryList;
        entryList = new ArrayList<T>();
        if (0 < list.size())
        {
            for (int i = 0; i < list.size(); i++)
            {
                T entity = clazz.newInstance();
                Map<String, Object> map = list.get(i);
                for (Map.Entry<String, Object> tempEntry : map.entrySet())
                {
                    String fieldName = tempEntry.getKey().toLowerCase();
                    Object fieldValues = tempEntry.getValue();
                    // ReflectionUtils.setFieldValue(entity, fieldName, fieldValues);
                    BeanUtils.setProperty(entity, fieldName, fieldValues);
                }
                entryList.add(entity);
            }
        }
        return entryList;
    }
    
    /**
     * <一句话功能简述>将resultSet转化成list<Map<String,Object>> <功能详细描述>
     * 
     * @param resultSet
     * @return
     * @throws SQLException
     * @see [类、类#方法、类#成员]
     */
    private List<Map<String, Object>> handleResultSetoToMapList(ResultSet resultSet)
        throws SQLException
    {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        List<String> labelsList = getColumnLabels(resultSet);
        
        while (resultSet.next())
        {
            Map<String, Object> map = new HashMap<String, Object>();
            for (String columnLabel : labelsList)
            {
                Object value = resultSet.getObject(columnLabel);
                map.put(columnLabel, value);
            }
            
            list.add(map);
        }
        return list;
    }
    
    // 以下将很多公用的方法重构 抽取
    
    /**
     * <一句话功能简述>:获取结果集的columnLabel <功能详细描述>
     * 
     * @param rs
     * @return
     * @throws SQLException
     * @see [类、类#方法、类#成员]
     */
    private List<String> getColumnLabels(ResultSet rs)
        throws SQLException
    {
        List<String> labels = new ArrayList<String>();
        ResultSetMetaData metaData = rs.getMetaData();
        for (int i = 0; i < metaData.getColumnCount(); i++)
        {
            //获取列的别名
            labels.add(metaData.getColumnLabel(i + 1));
        }
        
        return labels;
    }
    
    /**
     * <一句话功能简述> 连接数据库 <功能详细描述>
     * 
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    public Connection getConn()
        throws Exception
    {
        String dirverName = null;
        String jdbcUrl = null;
        String user = null;
        String password = null;
        
        Properties propertoes = new Properties();
        InputStream is = getClass().getClassLoader().getResourceAsStream("jdbc.properties");
        propertoes.load(is);
        
        dirverName = propertoes.getProperty("driver");
        jdbcUrl = propertoes.getProperty("jdbcURL");
        user = propertoes.getProperty("user");
        password = propertoes.getProperty("password");
        
        Class.forName(dirverName);
        
        // 通过DriverManager的getConnection获取数据库连接
        Connection connection = DriverManager.getConnection(jdbcUrl, user, password);
        
        return connection;
    }
    
    /**
     * <一句话功能简述>释放数据库资源 <功能详细描述>
     * 
     * @param statement
     * @param conn
     * @param resultSet
     * @see [类、类#方法、类#成员]
     */
    public void releaseSource(Statement statement, Connection conn, ResultSet resultSet)
    {
        if (null != resultSet)
        {
            try
            {
                resultSet.close();
            }
            catch (SQLException e)
            {
                e.printStackTrace();
            }
        }
        
        if (null != statement)
        {
            try
            {
                statement.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        if (null != conn)
        {
            try
            {
                conn.close();
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值