千锋逆战班学习第44天
千锋逆战班学习第44天
努力或许没有收获,但不努力一定没收获,加油。
今天我学习了JDBC。
中国加油!!!武汉加油!!!千锋加油!!!我自己加油!!!
连接池
JDBC每次连接数据库,都要获得一个连接对象。每次创建一个连接对象,都是一个较大的资源,如果在连接量较大的场景下,会极大的浪费资源。容易内存溢出。
自定义连接池
Java中提供了一个接口DataSource,通过实现该接口,可以创建连接池
Druid(德鲁伊)
Druid 是目前比较流行高性能的,分布式列存储
- 亚秒级查询
- 实时数据注入
- 可扩展的PB级存储
- 多环境部署
- 丰富的社区
Druid配置
- 创建database.properties 配置文件
- 引入druid-1.1.5.jar
database.properties 文件配置
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/userinfo?useUnicode=true&characterEncoding=utf8
username=root
password=123456
#初始化连接
initialSize=10
#最大连接数量
maxActive=30
#最小空闲连接
minIdle=5
#超时等待时间以毫秒为单位
maxWait=5000
连接池工具类
package com.qf.day44.t2;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.xml.transform.Result;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class DBPoolUtils {
//连接池对象
private static DruidDataSource ds;
static {
Properties properties = new Properties();
InputStream is = DBPoolUtils.class.getResourceAsStream("/database.properties");
try {
properties.load(is);
//使用德鲁伊工厂创建连接池
ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
//在连接池中获得Connection
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
- 注意:连接池中获得的Connection是DruidPooledConnection实现类,调用的close()方法不是关闭资源,而是将资源放回池中!
Service(Biz/Business)
概念:用户要完成的一个业务功能,是由一个或多个的DAO调用组成。
软件、程序提供的一个功能都叫业务
业务层的实现
package com.qf.day44.t3;
/**
* Userinfo的业务逻辑层对象
*/
public class UserinfoServiceImpl {
/**
* 用户的注册功能(业务)
*/
public String register(Userinfo userinfo){//1.接收参数
UserinfoDaoImpl userinfoDao = new UserinfoDaoImpl();
//2.调用数据访问层对象的查询方法!
Userinfo check = userinfoDao.select(userinfo.getUser_name());
if(check!=null){//用户存在!~
return "用户名已存在!";
}
//3.调用数据访问层对象的新增方法
int result = userinfoDao.insert(userinfo);
//4.将操作结果返回给调用者
if(result >0 ){
return "注册成功!";
}else{
return "注册失败!";
}
}
/**
* 登录功能业务
*/
public Userinfo login(String user_name,String user_pwd){//收参
UserinfoDaoImpl userinfoDao = new UserinfoDaoImpl();
//2.调用数据访问层对象的查询方法
Userinfo userinfo = userinfoDao.select(user_name);
//3.接收结果,处理结果
if(userinfo!=null){//用户存在!
//检验查询到的用户密码和输入的密码是否一致!
if(userinfo.getUser_pwd().equals(user_pwd)){
return userinfo;
}
}
//4.响应给调用者结果
return null;
}
}
复用
- DAO数据访问操作复用
- 业务功能的复用 //不同的终端访问
15.4 转账案例
import day44.t4.Utils.DBUtil;
import day44.t4.dao.AccountDaoImpl;
import day44.t4.entity.Account;
import java.sql.Connection;
import java.sql.SQLException;
public class AccountServiceImpl {
private AccountDaoImpl accountDao = new AccountDaoImpl();
//转账功能
public String transfer(String fromNo,String password,String toNo,double money){//收参
String result = "转账失败";
//组织业务功能
Connection connection = null;
try {
connection = DBUtil.getConnection();
connection.setAutoCommit(false);//开启事务
Account fromAcc = accountDao.select(fromNo);
if (fromAcc == null) {
throw new RuntimeException("用户不存在");
}
if (!fromAcc.getPassword().equals(password)) {
throw new RuntimeException("密码不正确");
}
if (fromAcc.getBalance() < money) {
throw new RuntimeException("余额不足");
}
Account toAcc = accountDao.select(toNo);
if(toAcc == null){
throw new RuntimeException("对方账户不存在");
}
fromAcc.setBalance(fromAcc.getBalance() - money);
accountDao.updata(fromAcc);
toAcc.setBalance(toAcc.getBalance() + money);
accountDao.updata(toAcc);
result = "执行成功";
connection.commit();
}catch (Exception e){
e.printStackTrace();
try {
System.out.println("出现异常,回滚");
connection.rollback();
}catch (SQLException ex){
ex.printStackTrace();
}
}finally {
DBUtil.closeAll(connection,null,null);
}
return result;
}
}
解决转账事务问题
1、传递Connection:如果将Service获得的Connection对象,传递给DAO各个方法。可以。//BadSmell 臭味
定义接口是为了更容易更换实现!而将Connection参数定义在接口方法中,就会污染当前接口,而无法复用。JDBC-Connection。MyBatis使用SqlSession
2、单例:当前项目只能有一个客户端连接