1. JDBC
导入mysql-connector-java.jar包
注册驱动
Class.forName("com.mysql.jdbc.Driver");
建立连接
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "123456");
获取对象
Statement stat = con.createStatement();
执行sql语句
String sql ="select * from help_relation";
ResultSet result = stat.executeQuery(sql);
处理结果
while (result.next()){
System.out.println(result.getInt("help_topic_id")+"\t"+ result.getString("help_keyword_id"));
}
关闭连接
con.close();
stat.close();
2. DriverManager 连接
DriverManager驱动管理对象
- 注册驱动 registerDriver(Driver river) 注册给定的驱动 在上面注册中我们使用class.forname使用了一下Driver这个类,默认被使用就注册驱动 必须是mysql5之后才可以省略这个注册
- 获取数据连接 getConnection(url , user , password) url为jdbc:mysql://ip:端口/库名
3. Connection 连接对象
Connection数据库连接对象
- 获取普通执行者对象 createStatement()
- 获取预编译执行者对象 prepareStatement(String sql)
- 开启事务 setAutoCommit(boolean autoCommit); 参数为false 则开启事务
- 提交事务 commit()
- 回滚事务 rollback()
- 释放资源 close();
4. Statement 执行语句
Statement执行sql语句的对象
- 增删改 executeUpdate(String sql) 返回一个int 影响的行数 可以执行 insert、update、delete语句
- 查询 executeQuery(String sql) 返回值resultset对象 封装查询的结果 可以执行select语句
- 释放资源 close()
5. ResultSet 结果
ResultSet结果集对象
- 判断结果是否还有数据 next() 有数据返回ture,并索引向下移动一行
- get数据类型(“列名”) 返回指定列的指定数据类型结果 如getInt() getString()
- 释放资源 close()
6. 工具类
在src下创建config.properties 文件
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mysql
username=root
password=123456
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
private JDBCUtils() {
}
//2.声明需要的配置变量
private static String driverClass;
private static String url;
private static String usename;
private static String password;
private static Connection con;
//3.提供静态代码块 读取配置文件为变量赋值
static {
try {
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");
Properties prop = new Properties();
prop.load(is);
driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
usename = prop.getProperty("usename");
password = prop.getProperty("password");
//注册驱动
Class.forName(driverClass);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
con = DriverManager.getConnection(url, usename, password);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
return con;
}
public static void close(Connection con, Statement stat, ResultSet rs) {
if (con != null) {
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Connection con, Statement stat) {
if (con != null) {
try {
con.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (stat != null) {
try {
stat.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
其实就是封装一个连接和关闭工具类方法
7. SQL注入攻击
在之前我们使用Statement对象执行sql语句并且sql语句是拼接字符串而成的 不安全
为了解决这个问题我们使用 PreparedStatement预编译执行者对象 并且参数以?形式作为占位符
为占位符 问号 赋值的方法: setXxx(参数1,参数2)
- Xxx 为数据的类型
- 参数1 为 ?的下标 从1开始
- 参数2 为 ?的实际参数
内置setObject()
Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mysql", "root", "123456");
String sql = "delete from user where name = ?";
PreparedStatement pstm = con.prepareStatement(sql);
pstm.setString(1,"张三");
执行SQL语句
- 执行 inser update delete 语句 executeUpdate();
- 执行 select 语句 executeQuery();
8. 数据库连接池
数据库连接池负责分配 管理 释放数据库连接 它允许程序重复使用一个现有的数据库连接 而不是重新建立一个
9. 自定义数据库连接池
- 继承 DataSource 接口
- 准备一个容器 用于保存多个连接对象
- 定义静态代码块 获取多个连接对象并放入容器中
- 重写getConnection()方法 用于获取一个连接对象
- 定义一个getSize方法 获取连接池容器的大小
// 准备一个容器 用于保存多个连接对象
private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());
//定义静态代码块 获取多个连接对象并放入容器中
static {
for(int i=1;i<=10;i++){
Connection con = JDBCUtils.getConnection();
pool.add(con);
}
}
//重写getConnection()方法 用于获取一个连接对象
@Override
public Connection getConnection() throws SQLException {
if(pool.size() > 0 ){
Connection con = pool.remove(0);
return con;
}else {
throw new RuntimeException("连接数据已用尽");
}
}
//定义一个getSize方法 获取连接池容器的大小
public int getSize(){
return pool.size();
}
9.1. 归还连接
把连接对象归还给连接池
9.1.1. 继承方式
打印通过连接池创建的连对象的 class
System.out.println(con.getClass());
//class com.mysql.cj.jdbc.ConnectionImpl
接下定义一个类 继承 ConnectionImpl 类
public class return01 extends ConnectionImpl {
private Connection con;
private List<Connection> pool;
public return01(HostInfo hostInfo, Connection con, List<Connection> pool) throws SQLException {
super(hostInfo);
this.con = con;
this.pool = pool;
}
// 重写close方法 将连接对象 重写归还容器中
@Override
public void close() throws SQLException {
pool.add(con);
}
}
但DriverManager 获取的还是 ConnectionImpl 这个对象, 继承这种方法行不通的
9.1.2. 装饰设计模式
- 实现 Connection 接口
// 定义连接对象和连接容器的成员变量
private Connection con;
private List<Connection> pool;
//通过有参构造方法为成员变量赋值
public return02(Connection con,List<Connection> pool){
this.con=con;
this.pool=pool;
}
// 重写close方法
@Override
public void close() throws SQLException {
pool.add(con);
}
其他方法调用原本方法
装饰设计模式就是 重写需要的方法 其他方法则调用原来类的方法
9.1.3. 适配器设计模式
适配器设计模式 实现接口的所有方法 除了需要的方法 然后再建一个类 继承该实现类 再重新未实现的方法 (使用中间件)
- 定义适配类 实现 Connection 接口 定义为一个抽象类
- 定义连接对象的成员变量 Connection con
- 通过有参构造方法赋值
- 重写所有抽象方法 除了close
- 继承适配类 成员变量 Connection 和 连接容器
- 通过有参构造方法赋值
- 重写close方法
10. 动态代理
在不改变目标对象方法的情况下对方法进行增强
被代理对象: 真实的对象
代理对象: 内容中的一个对象
代理对象必须和被代理对象实现相同的接口
Student st = new Student();
/*
参数1 为 类加载器 和被代理对象使用相同的类加载器
参数2 为 接口类型Class数组 和被代理对象使用相同的接口
参数3 为 代理规则 完成代理增强的功能
*/
StudentInterface proxySt =(StudentInterface) Proxy.newProxyInstance(st.getClass().getClassLoader(), new Class[]{StudentInterface.class}, new InvocationHandler() {
/*
Student类中所有的方法都经过invoke方法
我们通过对方法继续判断
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method为类执行某个方法 args为方法的实际参数
if (method.getName().equals("study")) {
// 判断为某个方法
System.out.println("hello world");
return null;
} else {
// 如不是则按原本方法执行
return method.invoke(st,args);
}
}
});
// 代理对象执行方法
proxySt.eat("肉");
proxySt.study();
11. 以动态代理 规划连接
//重写getConnection()方法 用于获取一个连接对象
@Override
public Connection getConnection() throws SQLException {
if (pool.size() > 0) {
Connection con = pool.remove(0);
Connection proxycon= (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("close")){
pool.add(con);
return null;
}else {
return method.invoke(con,args);
}
}
});
return proxycon;
} else {
throw new RuntimeException("连接数据已用尽");
}
}
12. 开源数据库连接池
12.1. C3P0
导入jar包
导入配置文件到src目录下
创建 C3P0 连接池对象
DataSource dataSource=new ComboPooledDataSource();
- 获取数据库连接并使用
Connection con = dataSource.getConnection();
配置文件会自动加载 必须命名为 c3p0-config.xml 或 c3p0-config.properties
12.2. Druid
导入jar包
通过properties集合 加载配置文件
InputStream is = druiddemo01.class.getClassLoader().getResourceAsStream("笔记/jdbc/src/druid.properties");
Properties prop =new Properties();
prop.load(is);
- 通Druid连接池工厂类获取连接池对象
DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
- 通过连接池获取数据库对象
Connection con = dataSource.getConnection();
13. 自定义JDBC框架
DataBaseMetaData 数据库的源信息
- getDatabaseProductName() 获取数据库产品的名称
- getDatabaseProductVersion() 获取数据库产品的版本号
getParameterMetaData() 参数的源信息 预编译对象获取方法
- getParameterCount() 获取sql语句中参数的个数
getMetaData() 获取结果集的源信息 通过结果集对象获取
- getColumnCount() 获取列的总数
- getColumnName(int i) 获取列名