目录
连接写在静态代码块中
我的连接部分写在了连接数据库工具类静态代码块中
以上篇文章的spring三层架构的用户登录页面为例
我运行application后登录网页
因为连接写在了JDBCUnit工具类的静态代码块中,连接始终只是获取一次
这样就会导致一些后果
比如在工作时,服务器出了问题,为了模拟我现在将数据库的网络断开
再次访问网页,发现这时用户登录不上了,虚拟机被我断了网当然访问不了数据库
假设服务器修好了,现在再将虚拟机的网打开,再刷新,还是一样登录不上
所以连接写在这里就是有问题了,总不能我把故障修好了还是登录不上吧,必须要把连接的位置换个地方写
我们考虑, 有什么方法可以解决这个问题?
连接池
普通的jdbc数据库连接时,都需要花一定时间建立连接,每一次执行完成后需要断开连接,如果同时多处创建数据库连接,将会严重占用系统资源
连接池:在类中直接创建多次连接,需要建立数据库连接时,从连接池中拿出来一个,使用完再放回去
好处:
解决了断开服务器断开连接后不不能再次连接的问题,一条连接失效可以给你分配其他的连接;
首次加载会创建多次连接,所以相应时间慢一些,但是之后的连接速度得到飞速提升;
先来看看怎么创建连接池
dbcp2连接池:
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class DBCP2Util {
public static void main(String[] args) {
BasicDataSource bds = new BasicDataSource();
//配置连接池
bds.setInitialSize(5);
bds.setUrl("jdbc:mysql://master:3306/test");
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUsername("root");
bds.setPassword("123456");
try {
//获取链接
Connection conn = bds.getConnection();
PreparedStatement ps = conn.prepareStatement("select * from login1");
ResultSet rs = ps.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("username"));
}
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
将改进写入项目中
工具类JDBCUtil用线程池改进的结果
import org.apache.commons.dbcp2.BasicDataSource;
import java.sql.*;
public class JDBCUtil {
public JDBCUtil(){
System.out.println("jdbc");
}
private static BasicDataSource bds;
static {
System.out.println("创建连接池");
bds = new BasicDataSource();
//配置连接池
bds.setInitialSize(5);
bds.setUrl("jdbc:mysql://master:3306/test");
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUsername("root");
bds.setPassword("123456");
}
public static Connection getConn(){
System.out.println("获取连接");
Connection conn=null;
try {
conn = bds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
}
bean层:储存dao层在数据中查询到的用户信息
import lombok.*;
//set,get方法,构造方法有参无参,toString方法
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User
{
private String userid;
private String username;
private String password;
}
数据访问层dao
import comshujia.spring.mvc.Until.JDBCUtil;
import comshujia.spring.mvc.bean.User;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
public class UserDao {
public User loginDao(String username){
//查询数据库,将查询到的信息存储 ->User(id,username,password)
//这里先将user定义为null,如果后面查询不到用户信息就返回空的user
User user = null;
try {
Connection conn = JDBCUtil.getConn();
String sql="select * from login1 where username=?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1,username);
ResultSet rs = ps.executeQuery();
if(rs.next()){
//这里我们需要新创建一个user,因为上面的为空会报空指针异常
user = new User();
user.setUserid(rs.getString("userid"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
}
//关闭上面的连接
rs.close();
ps.close();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
return user;
}
}
业务逻辑层service
import comshujia.spring.mvc.bean.User;
import comshujia.spring.mvc.dao.UserDao;
//验证登录能否成功
public class UserService {
public String loginService(String username,String password){
UserDao userDao = new UserDao();
//验证用户是否存在
User user = userDao.loginDao(username);
if(user==null){
return "用户不存在";
}
if(!user.getPassword().equals(password)){
return "密码错误";
}
// 验证用户码是否正确
return "登录成功";
}
}
表现层controller
import comshujia.spring.mvc.service.UserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserConntroller {
@RequestMapping("/userlogin")
public String userlogin(String username,String password){
//登录成功还是失败需要业务逻辑层的验证
UserService userService = new UserService();
String message = userService.loginService(username,password);
return message;
}
}
我们再来模拟一些场景:
1.输入正确的用户名密码
2.输入错误的密码
3.输入不存在的用户
4.断开服务器后连接
这些是断开连接后刷新网页的情况
当我再次启动服务器网络,刷新网页
登录成功,也获得了新的连接
需要注意的是Dao层,在使用完连接后记得关闭,要是连接超过了连接池设置的最大连接,其他的进程都会等待