前言:
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():返回驱动驱动程序的名称。
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();
}
}
}
}