JDBC
JDBC基础
概念
java database connectivity java连接数据库
本质
就是可以连接不同的数据库 就像jvm一样可以在不同的操作系统上面运行
基本步骤
需要导包使用 mysql的jar包
//1、注册驱动 告诉程序使用那种数据库
Class.forname("com.mysql.jdbc.Driver");
//2 获取连接对象
DriverManager.getConnection("jdbc:mysql://localhost/需要连接的数据库名",账号,密码);
//3 获取执行者对象
conn.createStatement();
//4 执行得到结果
statement.executeQuery("sql语句");
//5; 处理结果
rs.next();
//6 释放资源
rs.close();
conn.close();
statement;
使用到的对象:
DriverManager 驱动对象
作用:注册驱动 获取连接对象
Connection 连接对象
获取执行sql语句的对象 1、statement(一般不使用了,这个可以通过在输入框拼接字符串注入攻击) 2、prepareStatement(不能被注入sql攻击)
可以管理事务
Statement 执行对象
执行sql语句
executeQuery(sql) 查询
executeUpdate(sql) 增删改
ResultSet 结果集对象
next() :可以判断结果集下一行是否有数据
getXxx(“列名”) :可以得到改列的值 xxx代表数据类型
jdbc工具类
实现基本的操作一般都会使用这些相同的步骤,所以我们可以将这些步骤提取到工具类中,然后使用工具类调用方法就可以了
1、静态代码块加载配置文件 配置文件里面存放连接数据库的一些信息 加载后连接数据库 加载驱动即可
配置文件中
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/数据库名
username=root
password=自己数据库的密码
2、获取连接对象 静态方法
3、提供释放资源的静态方法 增删改只有两个对象需要释放 查询需要三个 需要两个方法,不过两个参数的方法可以通过调用三个参数的方法,传一个空参和需要释放的两个参数进去就可以了
public class JDBCUtils {
private static String url;
private static String username;
private static String password;
static {
//1 加载properties配置文件,获取连接数据库的相关参数,4个
//1.1 创建Properties对象
Properties properties=new Properties();
//1.2 调用load方法加载文件
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
try {
properties.load(is);
//1.3 根据key获取value值
String driverClass = properties.getProperty("driverClass");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//2 注册驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
//3 获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,password);
}
//4 释放资源
public static void close(Statement statement,Connection connection){
close(null,statement,connection);
}
public static void close(ResultSet rs, Statement statement,Connection connection){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
sql注入漏洞
原因:上面提过 如果使用Statement对象执行sql语句的话,如果sql中拼接了sql中的关键字就会出现漏洞
解决:使用prepareStatement执行sql语句对象
在获取preparestatement的时候将sql语句传进去进行预编译,
使用:在sql语句中需要传递参数的地方使用**?**占位符,有几个参数就写几个?
然后使用**executeQuery()**查询或者使用executeUpdate()执行得到resultset结果集
事务管理
一组sql语句同时成功或者同时失败
之前提过connection对象的三种方法
**conn.sutAutoCommit(false)😗*设置不自动提交 表示开启事务
**conn.commit()😗*提交事务
**conn.rollback()😗*回滚事务
操作:
一般结合批量操作
我们可以结合try、catch、finally使用
try写人批量操作 和提交事务
catch里面写回滚事务
finally里面写释放资源
就是如果事务操作失败回滚到原始状态 如果没有出错就提交
jdbc高级
数据库连接池
和线程池也是一样的 存储多个连接对象 提高效率 频繁创建和释放连接浪费时间
第三方数据库连接池
c3p0
步骤:
【前提】导入c3p0依赖jar包
c3p0-0.9.5.2.jar、mchange-commons-java-0.2.12.jar
【第一步】将c3p0-config.xml配置文件复制到src中(位置和名称是固定的)
【第二步】创建ComboPooledDataSource核心对象
//【第二步】创建ComboPooledDataSource核心对象
ComboPooledDataSource dataSource=new ComboPooledDataSource();
//【第三步】获取连接
Connection connection = dataSource.getConnection();
后面都是基操
注意:第三方连接池的是否资源close方法是归还连接 不是关闭数据库连接
配置文件名和位置都是固定的
Druid(使用较多)
步骤
【前提】导入druid依赖jar包
【第一步】在src编写配置文件,名称任意,一般叫做druid.properties
【第二步】使用Properties对象加载配置文件
【第三步】使用DruidDataSourceFactory工厂创建连接池对象
【第四步】获取连接
配置文件内容
# 基础连接参数,名称是固定
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhostd:3306/jdbc
username=root
password=root
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 等待超时时间
maxWait=3000
代码实现
//【第一步】在src编写配置文件,名称任意,一般叫做druid.properties
//【第二步】使用Properties对象加载配置文件
Properties properties=new Properties();
InputStream is = DataSourceTest.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(is);
//【第三步】使用DruidDataSourceFactory工厂创建连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//【第四步】获取连接
Connection conn = dataSource.getConnection();
System.out.println(conn);
}
连接池工具类
和jdbc基础中的工具类操作一样 不同的sql语句执行操作都是一样 这样频繁操作我们就可以提取到工具类中
1、将加载属性文件和创建连接池对象放到static静态代码块中 只执行一次
2、提供一个获取连接的静态方法
3、提供一个获取连接池的静态方法
4、提供一个释放资源的方法
代码和基础内容的操作差不多
自定义连接池
和自定义线程池也是差不多的原理
需要实现DataSource的接口
在静态代码块中实现给连接池创建连接对象的步骤以及加载配置文件和驱动的步骤
里面获取连接的方法是pool.remove()
注意:自定义连接池的释放方法close不是归还连接而是关闭连接
后面可以根据动态代理的方式解决这个方法 动态代理将close的方法里面实现pool.add(conn)就将连接对象归还了
设计模式
装饰者设计模式
就是不改变原有类方法对其方法进行增强
要求:实现接口的所有方法
弊端:需要重写的方法太多,麻烦
适配器模式
解决的问题:解决重写方法太多的问题,不过前提要有一个模板类,不然自己要写一个模板
要求:需要一个类去实现接口,重写所有的方法,然后我们的类只需要继承这个模板类就行,然后对这个需要增强的方法进行增强就可以了。
弊端:没有模板直接凉凉
动态代理方法 重要!!
理解:就是不改变原有类中的方法,然后对齐实现方法增强
解决了前面几种设计模式的弊端了
要求:代理对象和目标对象实现相同的方法,这样就有了相同的方法
比如:在获取连接对象的时候,连接对象使用close方法是关闭连接,这样我们就可以用动态代理连接对象,如果执行close方法的时候,使用pool.add(conn)归还连接就可以
语不明意!
上代码!!! 建议多敲多敲多敲多敲几遍 自然就悟了
//2 创建代理对象
/**
* ClassLoader loader:类加载器,用来在内存中生成代理对象的Class对象,跟目标对象使用一样的类加载器就行了
* Class<?>[] interfaces:原始对象实现的接口们,用来规定代理对象需要和目标对象实现相同的接口,那么就有相同的方法(功能)
* InvocationHandler h:是一个接口,该接口内部有一个invoke方法,用来处理代理逻辑。调用代理对象的任何方法,invoke方法都会执行。
*/
Connection proxyConnection = (Connection) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
/**
* @param proxy 代理对象,就是proxyConnection
* @param method 将来调用代理对象的方法对象,这个参数的目的就是用来反射调用原始对象对应的方法
* @param args 将来调用代理对象方法传递进来的参数
* @return 哪里调用代理对象的方法就返回到哪
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//处理增强的逻辑
//System.out.println(proxy); //不要打印,因为打印proxy相当于调用了proxy.toString(),形成了死递归。
//System.out.println(method);
//System.out.println(Arrays.toString(args));
//如果是close方法,那么就增强“归还连接”
if(method.getName().equals("close")){
System.out.println("归还连接...");
return null;
}
jdbcTemplate工具类
不那么重要,因为只是简化了查询语句,很局限,不实用, 后面用Mybatis框架可以将很多东西都结合到一起
步骤:需要导入五个jar包
构造方法需要一个数据库连接池
方法updata query queryForObject(返回一个对象)