四川做网站的,建网站卖虚拟资源需要怎么做,企业网站建设企业,如何打开图片工具wordpressSharding-JDBC系列
1、Sharding-JDBC分库分表的基本使用
2、Sharding-JDBC分库分表之SpringBoot分片策略
3、Sharding-JDBC分库分表之SpringBoot主从配置
4、SpringBoot集成Sharding-JDBC-5.3.0分库分表
5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表
6、【… Sharding-JDBC系列
1、Sharding-JDBC分库分表的基本使用
2、Sharding-JDBC分库分表之SpringBoot分片策略
3、Sharding-JDBC分库分表之SpringBoot主从配置
4、SpringBoot集成Sharding-JDBC-5.3.0分库分表
5、SpringBoot集成Sharding-JDBC-5.3.0实现按月动态建表分表
6、【源码】Sharding-JDBC源码分析之JDBC
前言
《Sharding-JDBC系列》的前5篇博文分析了Sharding-JDBC的使用本篇带大家从源码的角度整体的熟悉Sharding-JDBC的实现原理。从Sharding-JDBC 5.1.2 版本开始提供了原生JDBC驱动ShardingSphereDriver。
JDBC
2.1 JDBC概述
JDBCJava DataBase Connectivity是java连接数据库操作的原生接口API为开发者访问数据库提供标准的接口。各数据库厂商依照JDBC规范实现规范中的接口实现数据库的连接。Java开发者使用同样的访问代码配置不同的Driver、url以及账号即可实现不同数据库厂家的数据库连接。 2.2 JDBC组成
JDBC是由一组用Java语言编写的类和接口主要有DriverManager、Driver、Connection、Statement、ResultSet等。
使用JDBC连接数据库的步骤包含以下步骤
1加载JDBC驱动程序使用Class.forName()方法加载特定数据库的JDBC驱动程序即对应数据库插件中实现Driver接口的类 如 Mysql8之前为com.mysql.jdbc.Driver Mysql8的com.mysql.cj.jdbc.Driver Oracle的oracle.jdbc.driver.OracleDriver 2创建Connection数据库连接使用DriverManager.getConnection()方法返回一个Connection创建一个数据库连接对象。该方法需要指定数据库的连接字符串、用户名和密码
3创建Statement对象通过数据库连接对象Connection创建一个Statement对象用于执行SQL语句 也可以通过数据库连接对象Connection预编译SQL语句获得一个PreparedStatement对象。该方式通常与动态SQL语句结合使用获得PreparedStatement对象后给动态SQL语句中的占位符赋值。使用该方式不会有SQL注入的风险。 4执行SQL语句使用Statement对象执行SQL语句包括插入、查询、更新和删除等操作。如果是查询操作返回ResultSet对象
5关闭数据库连接使用数据库连接对象Connection的close()方法关闭数据库连接
2.3 JDBC使用
以下以MySQL为例讲解一下JDBC的使用。
2.3.1 使用创建Statement的方式
SpringBootTest
public class Test {org.junit.jupiter.api.Testpublic void mysqlTest() throws Exception {// 1、加载启动Class.forName(com.mysql.cj.jdbc.Driver);String url jdbc:mysql://localhost:3306/test;String username root;String password 123456;// 2、获取Connection对象Connection connection DriverManager.getConnection(url, username, password);String sql select * from tb_user;// 3、创建Statement对象Statement statement connection.createStatement();// 4、执行Sql。查询语句返回ResultSetResultSet resultSet statement.executeQuery(sql);// 5、处理结果集while(resultSet.next()) {System.out.println(name : resultSet.getString(name));}// 6、关闭数据库连接statement.close();connection.close();}}
2.3.2 使用PreparedStatement的方式 org.junit.jupiter.api.Testpublic void mysqlTest2() throws Exception {// 1、加载启动Class.forName(com.mysql.cj.jdbc.Driver);String url jdbc:mysql://localhost:3306/test;String username root;String password 123456;// 2、获取Connection对象Connection connection DriverManager.getConnection(url, username, password);String sql insert into tb_user(name, state) values(?, ?);// 3、预编译SQL语句没有执行SQL// 此处传入两个参数值第二个参数为Statement.RETURN_GENERATED_KEYS指定返回数据库生成的主键PreparedStatement statement connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);// 占位符赋值statement.setString(1, 王五);statement.setString(2, 1);// 4、执行Sql此处不需要再传入SQL语句。执行更新操作返回操作成功的记录数int rs statement.executeUpdate();// 5、获取生成的主键ResultSet generatedKeys statement.getGeneratedKeys();// 移到结果集的下一行generatedKeys.next();System.out.println(执行结果 : rs 记录主键 generatedKeys.getInt(1));// 6、关闭数据库连接statement.close();connection.close();} 1通过Connection的prepareStatement()方法可以在第二个参数中指定Statement.RRTURN_GENERATED_KEYS获取数据库表中设置的自动生成的主键值 2可以通过PreparedStatement的addBatch()方法实现对数据库的批量操作 2.4 JDBC原理
2.4.1 JDBC的驱动程序
JDBC的驱动程序为实现了java.sql.Driver接口的类。如com.mysql.cj.jdbc.Driver。当使用Class.forName()将对应的驱动类加载到元空间后会执行类的static静态代码段。源码如下
package com.mysql.cj.jdbc;import java.sql.DriverManager;
import java.sql.SQLException;public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException(Cant register driver!);}}
}
在static静态代码段中new一个Driver并通过DriverManager.registerDriver()将Driver注册到DriverManager中。DriverManager中使用一个静态的线程安全的List常量保存进一步封装的Driver对象。
package java.sql;public class DriverManager {// 线程安全的静态集合常量存放Driverprivate final static CopyOnWriteArrayListDriverInfo registeredDrivers new CopyOnWriteArrayList();public static synchronized void registerDriver(java.sql.Driver driver)throws SQLException {registerDriver(driver, null);}public static synchronized void registerDriver(java.sql.Driver driver,DriverAction da)throws SQLException {// 将driver封装成DriverInfo保存到registeredDrivers集合中if(driver ! null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));} else {// This is for compatibility with the original DriverManagerthrow new NullPointerException();}println(registerDriver: driver);}
}class DriverInfo {final Driver driver;DriverAction da;DriverInfo(Driver driver, DriverAction action) {this.driver driver;da action;}Overridepublic boolean equals(Object other) {return (other instanceof DriverInfo) this.driver ((DriverInfo) other).driver;}Overridepublic int hashCode() {return driver.hashCode();}Overridepublic String toString() {return (driver[className driver ]);}DriverAction action() {return da;}
}Driver中的主要方法
1boolean acceptsURL(String url)查询驱动程序是否认为它可以打开到给定url的连接 Driver制定自己能够连接的url的协议只有符合自己协议形式的url返回true反之返回false。 2Connection connect(String url, Properties info)试图创建一个到给定url的数据库连接
2.4.2 创建Connection数据库连接
通过DriverManager的getConnection()方法获取一个Connection对象。源码如下
package java.sql;public class DriverManager {// Driver集合private final static CopyOnWriteArrayListDriverInfo registeredDrivers new CopyOnWriteArrayList();CallerSensitivepublic static Connection getConnection(String url,String user, String password) throws SQLException {java.util.Properties info new java.util.Properties();if (user ! null) {info.put(user, user);}if (password ! null) {info.put(password, password);}return (getConnection(url, info, Reflection.getCallerClass()));}/*** 公共的获取Connection的方法*/private static Connection getConnection(String url, java.util.Properties info, Class? caller) throws SQLException {/** 当callerCl为null时我们应该检查应用程序的间接调用此类的类加载器* 以便可以从这里加载rt.jar之外的JDBC驱动程序类*/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 \));// 浏览已加载的Driver尝试建立连接。记录引发的第一个异常SQLException reason null;// 遍历Driverfor(DriverInfo aDriver : registeredDrivers) {// 如果权限不足跳过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 (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);}}
使用注册的Driver以及传入的url、用户信息尝试连接数据库获取一个Connection对象。
2.5 JDBC小结
JDBC通过DriverManager管理Driver并提供了Driver、Connection、Statement、PreparedStatement、ResultSet等API接口不同的数据库提供商实现对应接口实现对数据库的连接、SQL语句的执行等。
ShardingSphereDriver SpringBoot集成Sharding-JDBC-5.3.0分库分表-CSDN博客 在这篇博文介绍了Sharding-JDBC-5.3.0分库分表的基本使用。示例的application.yml配置信息为
server:port: 8080
spring:main:# 处理连接池冲突allow-bean-definition-overriding: truedatasource:driver-class-name: org.apache.shardingsphere.driver.ShardingSphereDriverurl: jdbc:shardingsphere:classpath:sharding.yml
即对应的Driver为ShardingSphereDriverurl指向shardingsphere的配置文件sharding.yml。
ShardingSphereDriver的源码如下
package org.apache.shardingsphere.driver;public final class ShardingSphereDriver implements Driver {private static final int MAJOR_DRIVER_VERSION 5;private static final int MINOR_DRIVER_VERSION 1;// 数据库连接缓存private final DriverDataSourceCache dataSourceCache new DriverDataSourceCache();static {try {// 注册到DriverManagerDriverManager.registerDriver(new ShardingSphereDriver());} catch (final SQLException ex) {throw new DriverRegisterException(ex);}}/*** 在hikari的DriverDataSource或其他连接池中会通过DriverManager.getDriver(url)获得该ShardingSphereDriver* 然后调用ShardingSphereDriver.connect()获得数据库连接*/Overridepublic Connection connect(final String url, final Properties info) throws SQLException {return acceptsURL(url) ? dataSourceCache.get(url).getConnection() : null;}/*** ShardingSphereDriver的url中必须是以jdbc:shardingsphere:开头* param url* return*/Overridepublic boolean acceptsURL(final String url) {return null ! url url.startsWith(jdbc:shardingsphere:);}Overridepublic DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) {return new DriverPropertyInfo[0];}Overridepublic int getMajorVersion() {return MAJOR_DRIVER_VERSION;}Overridepublic int getMinorVersion() {return MINOR_DRIVER_VERSION;}/*** 不符合JDBC标准* return*/Overridepublic boolean jdbcCompliant() {return false;}Overridepublic Logger getParentLogger() {return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);}
}1在static静态代码段中new一个ShardingSphereDriver注册到DriverManager中
2在acceptsURL(String url)方法中判断url是否以jdbc:shardingshpere:开头
3在connect()方法中从dataSourceCache中根据url获取一个Connection对象
ShardingSphere中的JDBC
在ShardingSphere框架中对于JDBC中提供的Driver、Connection、Statement等API接口进行了实现实现类分别为
1DriverShardingSphereDriver
2DataSourceShardingSphereDataSource
3ConnectionShardingSphereConnection
4StatementShardingSphereStatement
5PreparedStatementShardingSpherePreparedStatement
小结
限于篇幅本篇先分享到这里。
由于ShardingSphere采用了原生JDBC的驱动所以本篇重点讲解了JDBC及其原理。在此基础上结合ShardingSphereDriver的源码可以很清晰的对ShardingSphere的框架有一个整体的认识。
ShardingSphere框架就是通过实现JDBC中的接口在调用真实数据库的Statement执行SQL之前对SQL语句进行拦截解析结合分库分表规则执行对应真实数据库的SQL操作。 关于本篇内容你有什么自己的想法或独到见解欢迎在评论区一起交流探讨下吧。