要封装一个数据库框架,我们需要明白几个问题:
1. 对数据库的CURD操作是与获取连接等的放在一起,还是分开写。
2. 如何来保证事物
3. 如何实现通用性
其实答案很简单,首先,对于是否放在一起,其实看个人心情,怎样觉得代码优雅,就怎样写;其次保证事物实际上就是要保证我的每次操作都是同一个连接,那么可以使用ThreadLocal(实际很多框架,如Mybatis底层也是使用ThreadLocal来保证事物的);最后,实现通用性,可以采用继承或者接口。因此,我们可以写一个JdbcUtils,再写个BaseDao,并且使用c3p0连接池连管理连接,最后写一个UserDao来实现。
话不多说,直接上代码:
JdbcUtils
主要封装了获取连接、开启事物等
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.photograph_u.consts.JdbcConsts;
import java.sql.*;
public class JdbcUtils {
private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();
//c3p0连接池获取连接
private static ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql");
public static Connection getConnection() throws SQLException {
Connection conn = connectionThreadLocal.get();
if (conn == null) {
conn = dataSource.getConnection();
}
return conn;
}
//JDBC获取链接
/*
public static Connection getConnection() throws SQLException {
Connection conn = connectionThreadLocal.get();
if (conn == null) {
try {
Class.forName(JdbcConsts.DRIVER);
conn = DriverManager.getConnection(JdbcConsts.URL, JdbcConsts.USERNAME, JdbcConsts.PASSWORD);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
return conn;
}
*/
//获取预处理
public static PreparedStatement getPreparedStatement(Connection conn, String sql) throws SQLException {
if (conn != null) {
return conn.prepareStatement(sql);
}
return null;
}
//填充参数
public static void setParams(Object[] params, PreparedStatement pstm) throws SQLException {
if (pstm != null && params != null) {
for (int i = 1; i <= params.length; i++) {
pstm.setObject(i, params[i - 1]);
}
}
}
//开启事物
public static void beginTransaction() {
Connection conn = null;
try {
conn = getConnection();
conn.setAutoCommit(false);
connectionThreadLocal.set(conn);
} catch (SQLException e) {
connectionThreadLocal.remove();
close(conn, null, null);
throw new RuntimeException(e);
}
}
//提交事物
public static void commitTransaction() {
Connection conn = connectionThreadLocal.get();
if (conn != null) {
try {
conn.commit();
} catch (SQLException ex) {
try {
conn.rollback();
} catch (SQLException e) {
throw new RuntimeException(e);
}
throw new RuntimeException(ex);
} finally {
connectionThreadLocal.remove();
close(conn, null, null);
}
}
}
//释放资源
public static void close(Connection conn, PreparedStatement pstm, ResultSet rs) {
try {
if (rs != null) {
rs.close();
}
if (pstm != null) {
pstm.close();
}
if (connectionThreadLocal.get() == null) {
if (conn != null) {
conn.close();
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
BaseDao
主要封装了对数据库的增删查改
import com.photograph_u.util.CommUtils;
import com.photograph_u.util.JdbcUtils;
import org.apache.commons.beanutils.BeanUtils;
import java.sql.*;
import java.util.*;
public class BaseDao {
//查询封装到Bean
static <T> T queryToBean(String sql, Object[] params, Class<T> clazz) {
T object = null;
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstm = JdbcUtils.getPreparedStatement(conn, sql);
JdbcUtils.setParams(params, pstm);
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
object = clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
Object columnValue = rs.getObject(i);
if (columnValue != null && !("".equals(columnValue))) {
BeanUtils.setProperty(object, CommUtils.changeUnderlineToHumpName(columnName), columnValue);
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.close(conn, pstm, rs);
}
return object;
}
//查询封装到BeanList
public static <T> List<T> queryToBeanList(String sql, Object[] params, Class<T> clazz) {
List<T> objectList = new ArrayList<>();
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstm = JdbcUtils.getPreparedStatement(conn, sql);
JdbcUtils.setParams(params, pstm);
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
T object = clazz.newInstance();
for (int i = 1; i <= columnCount; i++) {
Object columnValue = rs.getObject(i);
String columnName = metaData.getColumnName(i);
if (columnValue != null && !("".equals(columnValue))) {
BeanUtils.setProperty(object, CommUtils.changeUnderlineToHumpName(columnName), columnValue);
}
}
objectList.add(object);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.close(conn, pstm, rs);
}
return objectList;
}
//查询封装到Map
public Map<String, Object> queryToMap(String sql, Object[] params) {
Map<String, Object> resultMap = null;
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstm = JdbcUtils.getPreparedStatement(conn, sql);
JdbcUtils.setParams(params, pstm);
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
resultMap = new LinkedHashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
Object columnValue = rs.getObject(i);
if (columnValue != null && !("".equals(columnValue))) {
resultMap.put(CommUtils.changeUnderlineToHumpName(columnName), columnValue);
}
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.close(conn, pstm, rs);
}
return resultMap;
}
//查询封装到mapList
public List<Map<String, Object>> queryToMapList(String sql, Object[] params) {
List<Map<String, Object>> mapList = new ArrayList<>();
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
pstm = JdbcUtils.getPreparedStatement(conn, sql);
JdbcUtils.setParams(params, pstm);
rs = pstm.executeQuery();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
while (rs.next()) {
Map<String, Object> resultMap = new LinkedHashMap<>();//这里为了保证查询顺序的正确性,不能直接使用HashMap
for (int i = 1; i <= columnCount; i++) {
Object columnValue = rs.getObject(i);
String columnName = metaData.getColumnName(i);
if (columnValue != null && !("".equals(columnValue))) {
resultMap.put(CommUtils.changeUnderlineToHumpName(columnName), columnValue);
}
}
mapList.add(resultMap);
}
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.close(conn, pstm, rs);
}
return mapList;
}
//增删改
public static int update(String sql, Object[] params) {
Connection conn = null;
PreparedStatement pstm = null;
int count;
try {
conn = JdbcUtils.getConnection();
pstm = JdbcUtils.getPreparedStatement(conn, sql);
JdbcUtils.setParams(params, pstm);
count = pstm.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
JdbcUtils.close(conn, pstm, null);
}
return count;
}
}
UserDao
具体的实现
import com.photograph_u.domain.User;
import java.util.Map;
public class UserDao extends BaseDao {
//检查用户是否存在
public boolean checkUser(String phone) {
String sql = "select count(*) as count from user where phone=? and is_deleted=0";
long count = (long) queryToMap(sql, new Object[]{phone}).get("count");//注意这里为long
return count == 1;
}
//添加用户
public boolean addUser(String phone, String password) {
String sql = "insert into user(phone,password) values(?,?)";
int count = update(sql, new Object[]{phone, password});
return count == 1;
}
//查询用户
public User queryUser(String phone, String password) {
String sql = "select id,nickname,head_image,sex,birthday,phone,school from user where phone=? and password=? and is_deleted=0";
User user = queryToBean(sql, new Object[]{phone, password}, User.class);
return user;
}
//修改密码字段
public boolean updatePassword(int userId, String password, String newPassword) {
String sql = "update user set password=? where password=? and id=? and is_deleted=0";
int count = update(sql, new Object[]{newPassword, password, userId});
return count == 1;
}
//重置密码
public boolean resetPassword(String phone, String newPassword) {
String sql = "update user set password=? where phone=? and is_deleted=0";
int count = update(sql, new Object[]{newPassword, phone});
return count == 1;
}
//查询用户
public User queryUserById(int userId) {
String sql = "select id,nickname,head_image,sex,birthday,phone,school from user where id=? and is_deleted=0";
User user = queryToBean(sql, new Object[]{userId}, User.class);
return user;
}
//修改个人信息
public boolean updateInfo(User user) {
String sql = "update user set nickname=?,sex=?,birthday=?,school=? where id=? and is_deleted=0";
Object[] params = {user.getNickname(), user.getSex(), user.getBirthday(), user.getSchool(), user.getId()};
int count = update(sql, params);
return count == 1;
}
//修改头像
public boolean updateHeadImage(int userId, String headImage) {
String sql = "update user set head_image=? where id=? and is_deleted=0";
int count = update(sql, new Object[]{headImage, userId});
return count == 1;
}
//查询用户头像和昵称
public Map<String, Object> queryUserHeadImageAndNickNameById(int userId) {
String sql = "select nickname,head_image from user where id=? and is_deleted=0";
Map<String, Object> resultMap = queryToMap(sql, new Object[]{userId});
return resultMap;
}
}
c3p0-config.xml
<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
<default-config>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
<named-config name="mysql">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/db_photograph_u</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</named-config>
</c3p0-config>