首先创建数据库表,插入2条测试数据
DAO
package com.godinsec;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
/**
* 访问数据的DAO接口 T:DAO处理的实体类的类型
*/
public interface DAO<T> {
/**
* 批量处理的方法
*/
void batch(Connection connection, String sql, Object[]... args)
throws SQLException;
/**
* 返回具体的一个值:总人数,某个人的信息,平均工资
*/
<E> E getForValue(Connection connection, String sql, Object... args)
throws SQLException;
/**
* 返回一个T的集合
*
* @return
*/
List<T> getForList(Connection connection, String sql, Object... args)
throws SQLException;
/**
* 返回一个T的对象
*
* @return
*/
T get(Connection connection, String sql, Object... args)
throws SQLException;
/**
* 增、删、改操作
*/
void update(Connection connection, String sql, Object... args)
throws SQLException;
/**
* 查询方法
*/
}
JDBCDAO
package com.godinsec;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
public class JDBCDAO<T> implements DAO<T>{
//QueryRunner是线程安全的
private QueryRunner queryRunner = null;
private Class<T> type;
public JDBCDAO(){
queryRunner = new QueryRunner();
type = ReflectionUtils.getSuperGenericType(getClass());
}
@Override
public void batch(Connection connection, String sql, Object[]... args)
throws SQLException {
queryRunner.batch(connection, sql, args);
}
//已经实现
@Override
public <E> E getForValue(Connection connection, String sql, Object... args)
throws SQLException {
return (E) queryRunner.query(connection, sql, new ScalarHandler(), args);
}
//已经实现
@Override
public List<T> getForList(Connection connection, String sql, Object... args)
throws SQLException {
return queryRunner.query(connection, sql,
new BeanListHandler<>(type), args);
}
//已经实现
@Override
public T get(Connection connection, String sql, Object... args)
throws SQLException {
return queryRunner.query(connection, sql, new BeanHandler<>(type), args);
}
//已经实现
@Override
public void update(Connection connection, String sql, Object... args)
throws SQLException {
queryRunner.update(connection, sql, args);
}
}
CustomerDao
package com.godinsec;
public class CustomerDao extends JDBCDAO<Customer>{
}
接下来看一个bean类Customer
private Integer id;
private String name;
private String email;
private Date birth;
最后看测试类的方法吧CustomerDaoTest
1、获取某个字段的值
@Test
public void testGetForValue() {
Connection connection = null;
try {
connection = JdbcTools.getConnection();
String sql = "select id,name,email,birth from customer where name = ?";
Object result = customerDao.getForValue(connection, sql,
"aaa");
System.out.println(result);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcTools.releaseDB(null, null, null, connection);
}
}
输出如下
1
2、获取某个对象
@Test
public void testGet() {
Connection connection = null;
try {
connection = JdbcTools.getConnection();
String sql = "select id,name,email,birth from customer where id=?";
Customer customer = customerDao.get(connection, sql, 1);
System.out.println(customer);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcTools.releaseDB(null, null, null, connection);
}
}
输出如下:
Customer [id=1, name=aaa, email=aaa, birth=2016-10-05]
3、获取某个对象集合列表
@Test
public void testGetForList() {
Connection connection = null;
try {
connection = JdbcTools.getConnection();
String sql = "select id,name,email,birth from customer";
List<Customer> customers = customerDao.getForList(connection, sql);
System.out.println(customers);
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcTools.releaseDB(null, null, null, connection);
}
}
[Customer [id=1, name=aaa, email=aaa, birth=2016-10-05], Customer [id=2, name=bbb, email=bbb, birth=2016-10-26]]
4、对数据库进行增删改操作
@Test
public void testUpdate() {
Connection connection = null;
try {
connection = JdbcTools.getConnection();
String sql = "insert into customer values(?,?,?,?)";
// 使用其方法
customerDao.update(connection, sql, 10, "ccc", "ccc",
"2011-10-20");
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcTools.releaseDB(null, null, null, connection);
}
}
再次查询数据库,记录增加一条
最后还有一个数据库工具类,以及一个反射工具类
JdbcTools
package com.godinsec;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JdbcTools {
// 开始事务
public static void beginTx(Connection connection) {
if (connection != null) {
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 回滚事务
public static void rollback(Connection connection) {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 提交事务
public static void commit(Connection connection) {
if (connection != null) {
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 使用数据库链接池来获取数据库链接--私有静态
private static DataSource dataSource = null;
// 数据库连接池只需要初始化一次就够了,因为一个项目只需要一个连接池就够了
static {
dataSource = new ComboPooledDataSource("helloc3p0");
}
public static Connection getConnection() throws Exception {
return dataSource.getConnection();
}
// 获取连接
public static Connection getConnection1() throws Exception {
String user = "root";
String password = "root";
String jdbcUrl = "jdbc:mysql:///mydatabase";
String driverClass = "com.mysql.jdbc.Driver";
Class.forName(driverClass);
Connection connection = DriverManager.getConnection(jdbcUrl, user,
password);
return connection;
}
// 关闭资源
public static void releaseDB(ResultSet resultSet,
PreparedStatement preparedStatement, Statement statement,
Connection connection) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
// 数据库链接池的connection对象并不是真的进行关闭
// 而是把链接归还到数据库连接池中
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
ReflectionUtils
package com.godinsec;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 反射的 Utils 函数集合
* 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
* @author Administrator
*
*/
public class ReflectionUtils {
/**
* 通过反射, 获得定义 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];
}
/**
* 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static<T> Class<T> getSuperGenericType(Class clazz){
return getSuperClassGenricType(clazz, 0);
}
/**
* 循环向上转型, 获取对象的 DeclaredMethod
* @param object
* @param methodName
* @param parameterTypes
* @return
*/
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
//superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
//Method 不在当前类定义, 继续向上转型
}
//..
}
return null;
}
/**
* 使 filed 变为可访问
* @param field
*/
public static void makeAccessible(Field field){
if(!Modifier.isPublic(field.getModifiers())){
field.setAccessible(true);
}
}
/**
* 循环向上转型, 获取对象的 DeclaredField
* @param object
* @param filedName
* @return
*/
public static Field getDeclaredField(Object object, String filedName){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
//Field 不在当前类定义, 继续向上转型
}
}
return null;
}
/**
* 直接调用对象方法, 而忽略修饰符(private, protected)
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
* @return
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
Object [] parameters) throws InvocationTargetException{
Method method = getDeclaredMethod(object, methodName, parameterTypes);
if(method == null){
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
}
method.setAccessible(true);
try {
return method.invoke(object, parameters);
} catch(IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return null;
}
/**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
* @param object
* @param fieldName
* @param value
*/
public static void setFieldValue(Object object, String fieldName, Object value){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
}
/**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
* @param object
* @param fieldName
* @return
*/
public static Object getFieldValue(Object object, String fieldName){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return result;
}
}
c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="helloc3p0">
<!-- 指定连接数据源的基本属性 -->
<property name="user">root</property>
<property name="password">root</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///mydatabase</property>
<!-- 若数据库中连接数不足时, 一次向数据库服务器申请多少个连接 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">5</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">10</property>
<!-- C3P0 数据库连接池可以维护的 Statement 的个数 -->
<property name="maxStatements">20</property>
<!-- 每个连接同时可以使用的 Statement 对象的个数 -->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>