三层架构
分层
层次 | 特点 |
---|---|
界面层(View) | 呈现给用户。 |
业务逻辑层(Service BLL) | 实现具体的业务逻辑,加工数据。 |
持久层(Dao) | 与数据库的增删改查相关的代码实现。 |
好处
1.为了实现高内聚、低耦合
2.使得程序可重用性和可移植性增强
缺点
1.降低了系统的性能
2.导致级联的修改
简单框架
面向接口编程
1.辨析
接口 | 特点 |
---|---|
接口 | 具体的一种代码结构 |
面向接口编程 | 一种思想,用于实现多态性,提升软件的灵活性和可维护性 |
2.优点
1)提升了代码的灵活性和复用性
2)良好的可扩展性
3)低耦合性
数据源与连接池
连接池概念
1)在系统启动的时候创建一批连接对象都保存在一个集合里面
2)如果需要数据库的连接,就可以从那这些对象中获得一个使用
3)数据库操作结束,在将这些对象放回集合中去,这样就可以节省资源
4)数据库连接池负责管理连接(分配连接和释放连接)
5)并没有真正的关闭资源
常见数据库连接池
1.C3P0
2.DBCP
C3P0的使用步骤
1.导入相应的jar包
2.设置连接池的参数
3.创建数据源,初始化数据库连接池
4.获取连接
此处C3P0的配置案例
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<named-config name="mysql-config">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/assetmanager?characterEncoding=utf-8</property>
<property name="user">root</property>
<property name="password">1234</property>
<!-- 初始化连接池中的连接数 -->
<property name="initialPoolSize">10</property>
<!--最大空闲时间 -->
<property name="maxIdleTime">30</property>
<!--连接池中保留的最大连接数 -->
<property name="maxPoolSize">100</property>
<!-- 连接池中保留的最小连接数-->
<property name="minPoolSize">10</property>
<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">3</property>
</named-config>
</c3p0-config>
C3P0使用案例
package com.hp.util;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 类描述:数据库操作工具类
* 版本号: 1.0.0
*/
public class JdbcUtils {
// 设置数据源(使用C3P0数据库连接池)
private static ComboPooledDataSource dataSource=new ComboPooledDataSource("mysql-config");
// 创建一个与事务相关的局部线程变量
private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
/**
* 方法描述:获取数据源
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 方法描述:获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
// 获取线程局部变量的值 connection
Connection conn=tl.get();
if(conn==null){
// 如果连接为空,则从数据库连接词池中获取连接
conn=dataSource.getConnection();
}
return conn;
}
/**
* 方法描述:开启事务
* @throws SQLException
*/
public static void beginTranscation()throws SQLException{
Connection conn=tl.get();
if(conn!=null){
throw new SQLException("不能重复开启事务");
}
// 获取连接
conn=getConnection();
// 关闭自动提交事务
conn.setAutoCommit(false);
// 将线程变量的值设置为connection
tl.set(conn);
}
/**
* 方法描述:提交事务
* @throws SQLException
*/
public static void commitTranscation() throws SQLException{
Connection conn=tl.get();
if(conn==null){
throw new SQLException("没有开启事务 不能提交");
}
// 提交事务
conn.commit();
// 关闭连接
conn.close();
// 移除此线程局部变量的值
tl.remove();
}
/**
* 方法描述:回滚事务
* @throws SQLException
*/
public static void rollbackTranscation() throws SQLException{
Connection conn=tl.get();
if(conn==null){
throw new SQLException("没有开启事务,不能回滚");
}
// 回滚事务
conn.rollback();
// 关闭连接
conn.close();
// 移除此线程局部变量的值
tl.remove();
}
}
DBUtil
介绍
1.是对JDBC做的简单封装,使用数据库连接池
主要类
1.QueryRunner
1)构造器QueryRunner():在事务中使用
2)构造器QueryRunner(DataSource):从数据库连接池中获取连接
3)update():执行增删改操作的调用
查询
1.query(sql,rsh,params):自动获取连接
2.query(conn,sql,rsh,params):手动获取连接
3.BeanHandler:获取单行数据,构造器需要一个Class类型的参数,用来把一行结果转换为指定类型的JavaBean对象。
4.BeanListHandler:获取多行数据,构造器需要一个Class类型的参数,用来把一行结果转换为指定类型的JavaBean对象,最终将多笔实例组成一个List集合,一堆JavaBean。
使用案例
返回单个记录:
public Admin login(Admin admin) {
// 1.编写sql语句
StringBuffer sql = new StringBuffer();
sql.append("SELECT * ");
sql.append("FROM admin ");
sql.append("WHERE adminName = ? AND adminPassword = ?");
// 2.创建一个QueryRunner对象,通过构造器提供数据源(从数据库中获取连接)
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
Admin result = null;
// 存放查询条件
Object[] params = {admin.getAdminName(),admin.getAdminPassword()};
try {
// 3.执行query查询操作,BeanHandler:将结果集中第一行数据封装到一个对应的JavaBean实例中
result = queryRunner.query(sql.toString(), new BeanHandler<>(Admin.class),
params);
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
返回多个记录:
public List<User> getAllUser() {
String sql = "SELECT * FROM user";
// 存放查询结果集合
List<User> users = null;
try {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
users = qr.query(sql, new BeanListHandler<>(User.class));
} catch (SQLException e) {
e.printStackTrace();
}
return users;
}
增删改时的使用:
public int addBank(Bank bank) {
String sql = "INSERT INTO bank(bankName,bankTel) VALUES(?,?)";
// 准备填充占位符的数组
Object[] params = {bank.getBankName(),bank.getBankTel()};
// 接收返回结果
int result = 0;
try {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
// 执行增删改操作同一调用update方法
result = qr.update(sql, params);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
获取单个值的使用(一般用于注册后获取自动增长的主键id):
public Long addUser(User user) {
StringBuffer sql = new StringBuffer();
sql.append("INSERT INTO `user` ");
sql.append("(userName,userPassword,realName,sex,tel,idCard,address) ");
sql.append("VALUES(?,?,?,?,?,?,?)");
Object[] params = {
user.getUserName(),
user.getUserPassword(),
user.getRealName(),
user.getSex(),
user.getTel(),
user.getIdCard(),
user.getAddress()
};
// Long 包装类型
Long result = null;
try {
QueryRunner qr = new QueryRunner(JdbcUtils.getDataSource());
// 第一种方式:获取新增的主键值,ScalarHandler获得单个值
//qr.update(sql.toString(), params);
//result = qr.query("SELECT LAST_INSERT_ID()", new ScalarHandler<>());
// 第二种方式:线程安全的、返回插入数据的主键
result = qr.insert(sql.toString(), new ScalarHandler<Long>(), params);
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
删除某一银行及其用户(此处采用事物):
public boolean deleteBank(int bankId) {
try {
// 开启事务
JdbcUtils.beginTranscation();
// 删除银行对应的资产信息
assetDao.deleteAssetByBankId(bankId);
//int i = 10 / 0;
// 删除银行信息
bankDao.deleteBank(bankId);
// 提交事务
JdbcUtils.commitTranscation();
return true;
} catch (Exception e) {
// 回滚事务
try {
JdbcUtils.rollbackTranscation();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
return false;
}
工具类
public class JdbcUtils {
// 设置数据源(使用C3P0数据库连接池)
private static ComboPooledDataSource dataSource=new ComboPooledDataSource("mysql-config");
// 创建一个与事务相关的局部线程变量
private static ThreadLocal<Connection> tl=new ThreadLocal<Connection>();
/**
* 方法描述:获取数据源
* @return
*/
public static DataSource getDataSource(){
return dataSource;
}
/**
* 方法描述:获取连接
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException{
// 获取线程局部变量的值 connection
Connection conn=tl.get();
if(conn==null){
// 如果连接为空,则从数据库连接词池中获取连接
conn=dataSource.getConnection();
}
return conn;
}
/**
* 方法描述:开启事务
* @throws SQLException
*/
public static void beginTranscation()throws SQLException{
Connection conn=tl.get();
if(conn!=null){
throw new SQLException("不能重复开启事务");
}
// 获取连接
conn=getConnection();
// 关闭自动提交事务
conn.setAutoCommit(false);
// 将线程变量的值设置为connection
tl.set(conn);
}
/**
* 方法描述:提交事务
* @throws SQLException
*/
public static void commitTranscation() throws SQLException{
Connection conn=tl.get();
if(conn==null){
throw new SQLException("没有开启事务 不能提交");
}
// 提交事务
conn.commit();
// 关闭连接
conn.close();
// 移除此线程局部变量的值
tl.remove();
}
/**
* 方法描述:回滚事务
* @throws SQLException
*/
public static void rollbackTranscation() throws SQLException{
Connection conn=tl.get();
if(conn==null){
throw new SQLException("没有开启事务,不能回滚");
}
// 回滚事务
conn.rollback();
// 关闭连接
conn.close();
// 移除此线程局部变量的值
tl.remove();
}
}