目录
五、 PreparedStatement和Statement的区别
一、什么是连接池
连接池:是一个容器,能够创建固定可重用数量连接对象,当着连接对象使用完毕,节省内存消耗归还到连接池中等待下一次利用!
二、 连接池作用
提供操作数据库性能
当用户发送请求,需要连接数据库,频繁创建连接对象,还需要释放,这种情况耗时,消耗内存空间大
启用连接池,用户发送请求,直接通过连接池操作里面已经创建好的连接对象,获取当前线程中的某个Connection,然后直接去操作数据库,使用完毕连接对象之后,从当线程中进行解绑,回到连接池中!
三、连接池技术
c3p0
dbcp
druid 德鲁伊--阿里开源项目
四、连接池的本质
连接池本质就是需要实现sun公司提供的DataSource实现类(物理数据源代替 DriverManager)
五、 PreparedStatement和Statement的区别
1)是否能够防止sql注入
PreparedStatement能够有效防止sql注入 (由于存在sql语句字符串拼接造成sql注入 不安全)
Statement:执行静态sql语句,语句中就会在字符串拼接,造成sql注入(不推荐)
2)是否高效(提高执行效率)
PreparedStatement 因为操作的参数化的sql语句,首先预编译---将sql语句存储在预编译对象中,根据占位符号类型进行赋值setXXX(int parameterIndex,实际参数(根据当前类型赋值))
直接通过预编译对执行sql语句,发送到数据库中进行操作 (执行sql效率高)Statement对象: 每次将拼接好的sql语句("硬编码") 进行执行 (执行sql效率低), 每次发送一个新的sql到数据库中进行执行
executeUpdate(String sql) / executeQuery(String sql)
六、JDBC原生操作步骤
1)导包 数据库的驱动jar包 mysql-connnector-java -版本号.jar
2)注册驱动
Class.forName("com.mysql.cj.jdbc.Driver") ;
3)获取数据库的连接对象----目前---使用DataSource替代了DriverManager
Connection conn = DriverManager.getConnection(
"jdbc:msyql://localhost:3306/库名?参数....",
"root",
"123456") ;
4)准备sql语句 :参数化的sql
String sql = "update account set name = ? where id = ?" ;//或者查询语句
5)获取预编译对象,并sql语句进行编译
PreparedStatement stmt = conn.prepareStatement(sql) ;
6)参数赋值
stmt.setString(1,"张三") ;
stmt.setInt(2,2) ;
7)执行并释放资源
stmt.executeUpdate() ; //int结果 //ResultSet结果集 stmt.executeQuery();stmt.close();
conn.close() ;
七、Druid连接池的操作步骤
1)导入连接池的第三方jar包 Druid-xxx(版本号).jar
2)编写连接池的配置文件(配置文件名称 任意即可 一般情况:jdbc.properties)
数据库的基本连接信息
driverClassName
url
username
password
initialSize 初始化数量
maxWait 最大等待时间
maxIdle:最大空闲数量
maxActive:最大激活数量
minIdle:最小空闲数量
3)通过DruidDataSourceFactory 工厂类---->创建DataSource(数据源)
静态方法:返回值就是DataSource
public static DataSource createDataSource(Properties prop)
4)读取jdbc.properties配置文件,获取资源文件的输入流对象,将输入流对象加载到Properties属性列表中
5)创建数据源对象-----获取getConnection()
1、提供druid.properties属性列表
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/ee_2106?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
username=root
password=123456
initialSize=5
maxActive=10
maxWait=3000
2、封装工具类
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* @author Kuke
* @date 2021/8/18
* 工具类---->DataSource----->获取数据库的连接对象 Connection以及后期管理事务
*
* 获取连接对象----静态方法
* 关闭资源-----静态方法
*/
public class DruidJdbcUtils {
//成员变量位置
private static DataSource ds ;
//为了保证线程安全:每一线程使用自己的Connection (张三/李四)
private static ThreadLocal<Connection> t1 = new ThreadLocal<>() ; //提供线程的局部变量保存连接对象
//构造方法私有化
private DruidJdbcUtils(){}
//静态代码块
static{
try {
//读取数据库连接池的配置文件----->通过DruidDataSourceFactory工厂类创建DataSource
//创建一个属性集合列表
Properties prop = new Properties() ;
//读取druid.properties
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().
getResourceAsStream("druid.properties");
//将资源文件所在的输入流加载列表中
prop.load(inputStream);
ds = DruidDataSourceFactory.createDataSource(prop);
//底层子实现类:DruidDataSource
System.out.println("数据源获取成功");
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
//提供静态方法:单独获取数据源
public static DataSource getDataSource(){
return ds ;
}
//获取连接对象Connection静态功能
public static Connection getConnection(){
//从ThreadLocal中获取局部变量的副本:Connection
/**
* public T get() :从线程中获取局部变量的副本!
*/
Connection conn = null ;
try {
conn = t1.get();
if(conn==null){
//如果空,需要从数据库的连接池中获取连接对象
conn = ds.getConnection();
//获取到之后,每一线程执行自己的Connection
//将获取到的连接对象 绑定到当前线程中
t1.set(conn);
}
//如果不为空,说明ThreadLocal线程中已经存在Connection
return conn ; //
} catch (SQLException e) {
e.printStackTrace();
}
return null ;
}
//关闭(释放资源)资源
public static void close(ResultSet rs, Statement stmt,Connection conn) {
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
//关闭之后,归还到连接池中,需要从当前线程中解绑
t1.remove();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void close( Statement stmt,Connection conn) {
close(null,stmt,conn);
}
//事务管理代码 --- 加入
public static void main(String[] args) {
DataSource ds = DruidJdbcUtils.getDataSource();
System.out.println(ds);
Connection connection = DruidJdbcUtils.getConnection();
System.out.println(connection);
}
}
八、单元测试
1、什么是单元测试
提供junit的内置注解@Test
@Before标记的方法
在执行@Test单元测试方法之前先执行 (初始化的操作)
@After标记的方法
在执行@Test单元测试方法之后执行(一般:资源的关闭)
2、 junit中的@Test和@Before,@After分别什么意思
junit:提供一种单元测试 需要针对业务功能进行测试:Service
service层:创建Service层对象 调用功能,传入实际参数----出现异常
首先应该判断:Dao层 是否能够正常操作数据----如果没有问题--->然后在service层中
这些注解:junit提供的内置注解
@Test:提供单元测试方法(编写的测试用例,测试某个模块的功能(查询/添加/删除/修改))
@Before:在执行单元测试方法之前先执行 (一些相关初始化操作:读配置文件)
@After:在执行单元测试方法之后执行(一些相关的释放资源的代码)
3、 本质
注解本质---->接口
1)编写一个类
2)编写一个单元测试方法,不需要参数,也不需要返回值类型
public void testFindAll()
3)方法上加入注解@TestDemo
4)编写测试代码----- 调用serivce 业务代码,获取数据
4、例计算器类
public class Calculator {
public int sum(int a,int b){
return a + b ;
}
public int sub(int a, int b){//减法
return a + b ;
}
}
测试类
public class TestDemo {
//测试查询功能
@Test
public void testFindAll(){
//调用service
AdminService adminService = new AdminServiceImpl() ;
List<Admin> list = adminService.getAllAdmin();
if(list!=null){
for (Admin admin : list) {
System.out.println(admin);
}
}
}
@Before
public void init(){
System.out.println("初始化操作...");
}
@After
public void close(){
System.out.println("释放相关的系统资源");
}
@Test
public void testSub(){
//创建计算器类
Calculator calculator = new Calculator() ;
int result = calculator.sub(10, 5);
//断言进行测试
//assertArrayEquals:测试数组相关(操作多个数据)
//assertEquals(预期结果,功能性测试结果)
Assert.assertEquals(5,result);
}
}