文章目录
jdbc的使用及过程分析
先再pom中导入mysql-connector;
使用全名去加载driver
com.mysql.cj.jdbc.Driver
使用应用加载器加载类路径下的实现类,静态代码块执行,Manager中的静态代码块会使用ServiceLoader去加载META-INF下的文件,不过并没有返回对象,因此使用全名去加载一定能成功注册;
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("Can't register driver!");
}
}
}
Manager的loadinitialDrivers就是里就是使用SPI机制,用ServiceLoader(不再双亲委派机制内)去加载并实例化;
/**
* 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");
}
private static void loadInitialDrivers() {
String drivers;
try {
drivers = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty("jdbc.drivers");
}
});
} catch (Exception ex) {
drivers = null;
}
// If the driver is packaged as a Service Provider, load it.
// Get all the drivers through the classloader
// exposed as a java.sql.Driver.class service.
// ServiceLoader.load() replaces the sun.misc.Providers()
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/* Load these drivers, so that they can be instantiated.
* It may be the case that the driver class may not be there
* i.e. there may be a packaged driver with the service class
* as implementation of java.sql.Driver but the actual class
* may be missing. In that case a java.util.ServiceConfigurationError
* will be thrown at runtime by the VM trying to locate
* and load the service.
*
* Adding a try catch block to catch those runtime errors
* if driver not available in classpath but it's
* packaged as service and that service is there in classpath.
*/
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
}
});
println("DriverManager.initialize: jdbc.drivers = " + drivers);
if (drivers == null || drivers.equals("")) {
return;
}
String[] driversList = drivers.split(":");
println("number of Drivers:" + driversList.length);
for (String aDriver : driversList) {
try {
println("DriverManager.Initialize: loading " + aDriver);
Class.forName(aDriver, true,
ClassLoader.getSystemClassLoader());
} catch (Exception ex) {
println("DriverManager.Initialize: load failed: " + ex);
}
}
}
缺点:这样会把代码写死,一旦更换Driver,就要修改代码,可以使用properties文件配置字符串,更换驱动的时候直接修改文件就可以;
直接使用默认DriverManger去加载
public class ExampleJDBC {
public static void main(String[] args) {
try {
Connection root = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata", "root", "967385");
PreparedStatement ps = root.prepareStatement("select * from mvcc;");
ResultSet resultSet = ps.executeQuery();
while (resultSet.next()) {
int num = resultSet.getInt(1);
String name = resultSet.getString("name");
System.out.println(num + name);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
由以上分析,DriverManager静态代码块会使用ServiceLoader去加载META-INF下的类,并实例化;并且,classForName失去了意义,因为最终都是DriverManager去加载实现类
存在多个Driver的情况,指定Driver?
假设存在多个Driver,mysql、Oracle都有,那么到底会加载哪个META-INF下的Driver呢?
DriverManager.registerDriver(new Driver());
注册就是添加到一个写时复制表中:
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
public static synchronized void registerDriver(java.sql.Driver driver,
DriverAction da)
throws SQLException {
/* Register the driver if it has not already been added to our list */
if(driver != null) {
registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
} else {
// This is for compatibility with the original DriverManager
throw new NullPointerException();
}
println("registerDriver: " + driver);
}
获取连接会尝试每个驱动,连接上就结束return;
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;
}
}
SQL注入
什么是sql注入?
SQL 注入其实就是恶意用户通过在表单中填写包含 SQL 关键字的数据来使数据库执行非常
规代码的过程。简单来说,就是数据「越俎代庖」(yuè zǔ dài páo)做了代码才能干的 事情。这个问题的来源是,SQL
数据库的操作是通过 SQL 语句来执行的,而无论是执行代 码还是数据项都必须写在 SQL 语句之中,这就导致如果我们在数据项中加入了某些
SQL 语 句关键字(比如说 SELECT、DROP 等等),这些关键字就很可能在数据库写入或读取数据 时得到执行。
原文链接:https://blog.csdn.net/weixin_40851188/article/details/89763872
如何防止SQL注?
https://blog.csdn.net/weixin_40851188/article/details/89763872*
jdbc是如何防止的?
(1)示例:
"insert into students (name) values ('Robert');DROP TABLE students;--"
修改为:
insert into student (name) values('drop table')
将statement换为 preparedStatement;
public class StatementT {
public static void main(String[] args) {
try {
Connection connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata", "root", "967385");
String sql="insert into mvcc values(?,?)";
PreparedStatement preparedStatement=connection.prepareStatement(sql);
preparedStatement.setInt(1,1);
preparedStatement.setString(2,"KumMing");
preparedStatement.execute();
} catch (SQLException e) {
e.printStackTrace();
}
}