本来想自己按着书本项目来做一遍的,在阅读代码时,无奈代码量实在太多而且没有详尽的指导,层次相当复杂,自己不清楚原理,不明白架构,对我自己来讲不会就不能硬着头皮上,所以做项目变成了源码阅读尴尬了。
导包配置步骤:
在画思维导图的时候,首要的就是数据库操作,源码利用了c3p0的连接方式,首先要明确用到的四个类
--jdk自带的类
javax.sql.DataSource
java.lang.ThreadLocal<Connection>
--apache dbutils工具类
org.apache.commons.dbutils.QueryRunner;
org.apache.commons.dbutils.handlers.BeanHandler
--c3p0操作库
com.mchange.v2.c3p0.ComboPooledDataSource
用的DButils包为commons-dbutils-1.4.jar
,jdk1.7
,c3p0-0.9.1.2.jar
参考了具体操作有大佬博客写得详细:https://blog.csdn.net/qq_27869123/article/details/81138638
不同于传统的JDBC操作,这个需要指定c3p0-config.xml
配置文件
具体内容如下,文件放在项目名/src根目录下
xml version="1.0" encoding="UTF-8"?>
<!--该文件用于配置数据库连接参数-->
<c3p0-config>
<default-config>
<property name="user">root</property>
<property name="password">root</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/itcaststore?useUnicode=true&characterEncoding=utf-8&useSSL=false
</default-config>
</c3p0-config>
同样位置还有一个叫merchantInfo.properties
的文件,但是不清楚其作用,删掉后也无影响,暂且不管,内容是:
p1_MerId=10001126856
keyValue=69cl522AV6q613Ii4W6u8K6XuW8vM1N6bFgyv769220IuYe9u37N4y7rI4Pl
responseURL=http://localhost:8080/itcaststore/callback
DataSource层初始化步骤:
写一个数据源工具类,完成数据源实例化、获取数据源、通过ThreadLocal键值对获取本线程对应Connection实例。
public class DataSourceUtils {
//ComboPooledDataSource 是c3p0封装了jdbc 对DataSource接口的实现。
//默认读取c3p0-config.xml配置信息,主机名端口号数据库名和用户名密码等
private static DataSource dataSource = new ComboPooledDataSource();
//ThreadLoacl对象,用当前线程作为key,存储每个线程对应的一个Connection对象
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
public static DataSource getDataSource() {
return dataSource;
}
/**
* 当DBUtils需要手动控制事务时,调用该方法获得一个连接
*/
public static Connection getConnection() throws SQLException {
Connection con = tl.get();
if (con == null) {
con = dataSource.getConnection();
tl.set(con);
}
return con;
}
/**
* 开启事务
*/
public static void startTransaction() throws SQLException {
Connection con = getConnection();
if (con != null)
con.setAutoCommit(false);
}
/**
* 从ThreadLocal中释放并且关闭Connection,并结束事务
*/
public static void releaseAndCloseConnection() throws SQLException {
Connection con = getConnection();
if (con != null) {
con.commit();
tl.remove();
con.close();
}
}
/**
* 事务回滚
*/
public static void rollback() throws SQLException {
Connection con = getConnection();
if (con != null) {
con.rollback();
}
}
}
该类除了获取实例外还定义了一些开启事务关闭实务回滚事务的方法。一般写代码都是用手动控制的方法,这些当是初始化DataSource配置就可以了。
Dao层步骤:
底层准备完,来写高层,本层主要QueryRunner利用DataSource进行数据库访问。
public class UserDao {
// 添加用户
public void addUser(User user) throws SQLException {
String sql = "insert into user(username,password,gender,email,telephone,introduce,activecode) values(?,?,?,?,?,?,?)";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
int row = runner.update(sql, user.getUsername(), user.getPassword(),
user.getGender(), user.getEmail(), user.getTelephone(),
user.getIntroduce(), user.getActiveCode());
if (row == 0) {
throw new RuntimeException();
}
}
// 根据激活码查找用户
public User findUserByActiveCode(String activeCode) throws SQLException {
String sql = "select * from user where activecode=?";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return runner.query(sql, new BeanHandler<User>(User.class), activeCode);
}
// 激活用戶
public void activeUser(String activeCode) throws SQLException {
String sql = "update user set state=? where activecode=?";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
runner.update(sql, 1, activeCode);
}
//根据用户名与密码查找用户
public User findUserByUsernameAndPassword(String username, String password) throws SQLException {
String sql="select * from user where username=? and password=?";
QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
return runner.query(sql, new BeanHandler<User>(User.class),username,password);
}
}
总体上看,实例化一个QueryRunner
都是利用一个DataSource
对象
addUser()
方法里用调用了QueryRunner
的update()
方法,并且返回一个int
类型返回码,该值是操作数据库后受影响的行数,插入数据没有影响则报错。
findUserByActiveCode()
方法里面调用了QueryRunner
的query()
方法中实例化一个BeanHandler
集合以及随后的activeCode
查询条件通配sql语句?号,用于返回符合条件的用户。再观察随后两个方法,不难发现QueryRunner
的使用套路,无论是查询还是更新,方法里面第一个参数必定是含有占位符?
的sql语句,如果是查询返回的应该是结果集,所以方法第二个参数必定为BeanHandler
,然后按照sql占位符的顺序排列好的参数一一放在其后。
说说BeanHandler
,因为JDBC返回的是Result对象,不同于直接用Resultset结果集next()循环操作的原生JDBC,BeanHandler
是直接把结果实体类封装成了javabean,丢回去一个实体类。就该项目来说,只是用BeanHandler
返回单个结果,至于怎么用这个东西返回一堆实体类呢?应该也能实现,有空试试。
感激乐于分享技术的巨人前辈们!