什么是jdbc
维基百科定义:
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC也是Sun Microsystems的商标[1]。JDBC是面向关系型数据库的。
通俗的说:JDBC就是java语言连接数据库的规范,每个数据库厂商的实现都遵守该规范进行实现。
JDBC为什么需要数据库驱动
1,数据库是一个产品,想要访问它,就得通过它的方式去连接它的方式去访问。就像我们写的接口,别人访问要按照我们的规则来。
2,底层采用自己的通信协议,每个数据库厂商都有自己的通信协议。
通过查阅《MySQL技术内幕InnoDB存储引擎》:mysql
常用的进程间通信方式有:管道,命名管道,命名字,TCP套接字,Unix域套接字。而MySQL提供的连接方式从本质上看都是上述提及的进程通信方式
1,TCP/IP
TCP/IP套接字的方式是MySQL在任何平台上都提供的连接方式,也是用的最多的。一般情况客户端一台机器去连接服务器另一台机器。两台机器之间就是通过TCP/IP连接。客户端会向服务器MySQL实例发出TCP/IP连接请求,并连接成功。
……
实现六大步骤
1,注册数据库驱动
Connection conn = null;
Statement stat = null;
ResultSet rs = null;
Class.forName("com.mysql.jdbc.Driver");
使用反射优点:
解耦
2,获取数据库连接
conn = DriverManager.getConnection("jdbc:mysql:///mydb5", "root", "root");
当系统中有多个驱动时,手动管理很麻烦,所以DriverManager类会帮我们管理
原理:
1,它会自己保存一份所有的驱动列表:
// List of registered JDBC drivers
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();
2,我们前面已经调用Class.forName(),系统已经加载了我们所需要的实现类
3,DriverManager加载进来时会执行以下静态语句
/**
* Load the initial JDBC drivers by checking the System property
* jdbc.properties and then use the {@code ServiceLoader} mechanism
*/
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
4,loadInitialDrivers方法会加载系统中已经加载的所有驱动Driver存放到刚刚那个list里面
然后我们调用getConnection时,它就会遍历列表的驱动,帮我们找到合适的驱动Driver并使用
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
String url, java.util.Properties info, Class<?> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
// synchronize loading of the correct classloader.
if (callerCL == null) {
callerCL = Thread.currentThread().getContextClassLoader();
}
}
if(url == null) {
throw new SQLException("The url cannot be null", "08001");
}
println("DriverManager.getConnection(\"" + url + "\")");
// Walk through the loaded registeredDrivers attempting to make a connection.
// Remember the first exception that gets raised so we can reraise it.
SQLException reason = null;
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
// if we got here nobody could connect.
if (reason != null) {
println("getConnection failed: " + reason);
throw reason;
}
println("getConnection: no suitable driver found for "+ url);
throw new SQLException("No suitable driver found for "+ url, "08001");
}
3,获取传输器
stat = conn.createStatement();
4,利用传输器,将程序构建的sql发送到数据库中执行,返回执行结果。
rs = stat.executeQuery("select * from account");
5,处理结果
while(rs.next()){
int id = rs.getInt(1);
String name = rs.getString("name");
double money = rs.getDouble("money");
System.out.println(id+name+money);
}
6,释放资源
rs.close();
防止sql注入
采用PreparedStatement 对象,优点如下:
1,可以防止sql注入攻击(先将sql骨架发给数据库编译下来,后面发送的只能是参数的值,即使传送特殊符号,也只会当成普通文本处理)。
2,通过方法来设置参数,省去了拼接sql语句的麻烦。
3,可以提高程序的效率(发送的骨架会被缓存下来,如果下次执行的sql与缓存中的相匹配,
就不再编译而是直接使用缓存中的语句,减少sql的编译;statement每次拼接好再发
送sql数据库,每次参数不同,整条sql也就不同,所以每次都需要编译)
为什么需要连接池
1, 用户每次请求动需要向数据库获得连接,而数据创建连接通常需要消耗相对较大的资源,通过连接池共享连接,减少开关连接的次数,提高程序的效率。
2,自定义连接池:(也可采用开源数据库连接池druid(阿里开源),c3p0(现在用的少了),HikariCP(springboot2.x默认支持))需要在使用完连接后记得不关闭连接,而是调用retrunconn方法将连接还回池中。
3,改造close 方法(a继承,b装饰 )目的:将连接还回去,而不是关闭
a
写一个类继承要改造的类,对于不想改造的方法不覆盖,对于想要改造的方法复写该方法,将代码改造为自己需要的逻辑代码。
这种方式只能在还没有对象的情况下使用,现在Connection对象已经存在了,再用继承复写的方式是不行的,所以我们不采用。
b
实现装饰设计模式:
(1)写一个装饰类, 要求装饰类和被装饰者所属的类实现同一个接口或者继承同一个父类
(2)装饰类必须提供构造方法接收被装饰者, 并将被装饰者保存在类的内部
(3)对于想要改造的方法直接进行改造, 对于不想改造的方法, 直接调用原有对象(被装饰者)上的方法