1.JDBC的入门级使用 这边就是说明一下jdbc是怎么使用的,以及涉及到的各个对象的注意事项。
import com.mysql.jdbc.NonRegisteringDriver;
import java.sql.*;
public class JdbcMain {
public static void main(String[] args){
Connection connection = null;
//预编译功能防止sql注入
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//注册驱动,注意这边必须要到入相应的jar包
//这边兄弟们肯定有疑问怎么反射一下就回加载呢?
//这边用了静态类我只要加载到这个文件那么DriverManager就会自己注册
/*public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}static {
try {
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}*/
//jdk5之后可以不写这个反射,直接就可以使用,感兴趣可以了解一下
//mysql-connector-java-5.1.37.jar!/META-INF/services/java.sql.Driver
Class.forName("com.mysql.jdbc.Driver");
//获取链接,返回的是链接对象
//1.这边重要就是链接中可以控制事务的开启关闭
//2.获取执行对象
//3.使用完成需要关闭链接,释放资源
connection = DriverManager.getConnection("jdbc:mysql://168.192.11.555/product","root","root");
//执行的语句对象
String sql = "select * from Hero";
//执行者对象,可以理解为操作sql的对象
//1.执行DML语句也就是增啥改的操作使用 executeUpdate() 这个返回值是影响的数量
//2.执行DDL语句也就是查询的操作使用 executeQuery();
这个返回的是结果集
//3.释放资源
preparedStatement = connection.prepareStatement(sql);
//返回的结果集
//这边注意的就是要释放资源
resultSet = preparedStatement.executeQuery();
while(resultSet.next()){
System.out.println(resultSet.getString("name"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(resultSet !=null){
resultSet.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
try {
if (preparedStatement!=null){
preparedStatement.close();
}
} catch (SQLException e) {
e.printStackTrace();
}if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}}}}
2.JDBC工具类 - 手敲 这边实际上没有多少知识点。但是还是要手动敲一下记忆才深刻
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
//无参构造
private JdbcUtils(){};
//数据库链接的必要参数
private static String driverName;
private static String url;
private static String username;
private static String password;
private static Connection con;
//从配置文件中读取数据然后加载到类里面static{
//获取输入流
InputStream resourceAsStream = JdbcUtils.class.getClassLoader().getResourceAsStream("mysqlProperties.properties");
//将流转化成对象
Properties properties = new Properties();
try {
properties.load(resourceAsStream);
driverName = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
//让类加载,初始化哪个数据库 其实就是初始化DriverManager
Class.forName(driverName);
} catch (Exception e) {
e.printStackTrace();
}finally {
if (resourceAsStream !=null){
try {
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}//创建链接public static Connection getConnection(){
try {
con = DriverManager.getConnection(url, username, password);
} catch (SQLException e) {
e.printStackTrace();
}return con;
}public static voidcloseConnection(Connection con, Statement statement, ResultSet resultSet){
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement !=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//关闭资源
public static voidcloseConnection(Connection con, Statement statement){
if(con!=null){
try {
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement !=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
值得注意的是配置文件的路径
【Java|JDBC (Java DataBase Connectivity )的基本使用】
文章图片
3.jdbc事务 这边很简单,知道一下就好。
//是否开启事务自动提交,这边false就是开启事务
connection.setAutoCommit(false);
//提交事务
connection.commit();
//回滚事务
connection.rollback();
4.自定义数据库连接池 这边的重点主要是实现DataSource这个接口。
这边有个值得深思的问题,就是我调用con.close的方法如何不是关闭连接而是,返回线程池呢?
- 第一种的想法就是继承jdbcConnection的思维,但是最后是行不通的。因为需要改动的类太多了。工作量太大
- 装饰者模式,就是在返回连接对象的时候,再次封装成一个新的类,在这个方法里面重写con.close方法
- 适配器模式,实际上和装饰者模式差不多的思维,只是多了一个中间的抽象类,这个抽象类里面还是调用除了close以外的方法。
- 动态代理模式。这是最好的方法,也是各个持久层框架里面常用的方法。后面我会介绍一下
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
/**
* 自定义数据库链接池,简单版
*/
public class MyJdbcPool implements DataSource {
//创建一个线程安全的连接池
private static List pool = Collections.synchronizedList(new ArrayList<>());
//初始化十条连接
static{
for (int i = 0;
i < 10;
i++) {
Connection connection = JdbcUtils.getConnection();
pool.add(connection);
}
}
@Override
public Connection getConnection() throws SQLException {
if(pool.size()>0){
Connection connection = pool.remove(0);
return connection;
}else{
new RuntimeException("数据库连接池耗尽");
}
return null;
}@Override
public Connection getConnection(String username, String password) throws SQLException {
return null;
}@Override
public T unwrap(Class iface) throws SQLException {
return null;
}@Override
public boolean isWrapperFor(Class> iface) throws SQLException {
return false;
}@Override
public PrintWriter getLogWriter() throws SQLException {
return null;
}@Override
public void setLogWriter(PrintWriter out) throws SQLException {}@Override
public void setLoginTimeout(int seconds) throws SQLException {}@Override
public int getLoginTimeout() throws SQLException {
return 0;
}@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
return null;
}
}
4.1 动态代理返回连接池 这是基于上面连接池的类修改的,那么我们这边就是对close做动态增强。让他返回连接池而不是关闭连接。
@Override
public Connection getConnection() throws SQLException {
if(pool.size()>0){
Connection connection = pool.remove(0);
Connection proxyInstance = (Connection) Proxy.newProxyInstance(this.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")) {
System.out.println("归还连接池");
pool.add(connection);
return null;
} else {
return method.invoke(connection, args);
}
}
});
return proxyInstance;
}else{
new RuntimeException("数据库连接池耗尽");
}
return null;
}
5.结束语 以上就是jdbc、以及连接池的基本使用,当然这边写的连接池只是丐版,很多不完善,诸如c3p0、druid等连接池都是很完善的数据连接池框架。但是实现的思路都是差不多的,感兴趣的同学可以看一下源码。提高自身的编码能力的唯一途径就是多看,多写。
最后还是要提示一下ResultSet是有专门的方法获取返回的值对象,然后通过反射的方式可以生成对应的bean对象。然后预处理对象也有专门的方法可以获取里面占位符的个数,从而和传入的对象进行一对一的赋值。jdbc高级部分有时间可以再次了解一下。
如有错误,多多指正!
推荐阅读
- MySQL学习笔记|MySQL8.0学习记录16 - 存储过程与函数对比
- #|4-MySQL原理-SQL执行原理
- 面试八股文|Spring Cloud知识
- 编程语言|2022,前端工具链十年盘点
- 网络|QUIC 是如何解决TCP 性能瓶颈的()
- 笔记|JAVA jdk安装笔记
- java|如果再写for循环,我就锤自己
- linux|MySQL数据库增删改查(基础操作命令详解)
- mysql优化|MySQL到底怎么优化?