JDBC
本系列为本人学习情况记录,部分资料来自老师课件或书籍摘录。
一、JDBC基本概念
- 一种用于执行SQL语句的Java API
- 可以为多种关系数据库提供统一访问
- 由一组Java语言编写的类和接口组成
二、使用
2.1 连接驱动
数据库 | 驱动程序类 | 来源 |
---|---|---|
MySQL | com.mysql.jdbc.Driver com.mysql.cj.Driver (MySQL6.0 以上使用) | mysql-connector-java-x.x.x.jar |
Oracle | oracle.jdbc.OracleDriver | ojdbcx.jar |
Access | sun.jdbc.odbc.JdbcOdbcDriver | JDK内置 |
注意:
- 这些类由JDBC使用,程序员并不会在程序中显式调用这些驱动类,所以必须编写代码告诉JVM加载它们
- Java 6 开始职称驱动程序的自动加载
2.2 连接到数据库
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
数据库 | 驱动程序类 |
---|---|
MySQL | jdbc:mysql://localhost:3306/数据库名称(MySQL 8.0版本之前) |
MySQL | jdbc:mysql://localhost:3306/数据库名称?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=GMT%2B8 |
Oracle | jdbc:oracle:thin:@localhost:1521:数据库的SID |
Access | jdbc:odbc:数据源名称 |
2.3 JDBC访问数据库的基础代码
public class Main{
public static void main(String[] args){
//1.加载连接驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得连接(连接到数据库) - 通过连接管理器创建连接对象
Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
//3.通过连接对象获取语句对象
Statement statement = connection.createStatement();
//操作
//执行完毕后,关闭打开的资源
statement.close();
connection.close();
}
}
Statement 常用方法
方法 | 作用 |
---|---|
int executeUpdate(String sql) | 可以执行插入、删除、更新等语句,或者是不返回任何内容的SQL语句 |
boolean execute(String sql) | 返回值为true时表示执行的是查询语句,可以通过getResultSet()获得结果集;返回值为false时执行的是更新语句或DDL语句 |
int getUpdateCount() | 获取更新的纪录数量 |
ResultSet executeQuery(String sql) | 执行SQL查询语句并返回ResultSet结果集对象 |
ResultSet常用方法
方法 | 作用 |
---|---|
boolean next()/boolean previous() | 将游标从当前位置向 下 / 上 移动一行 |
int getInt(int columnIndex)/int getInt(String columnLabel) | 以整形方式获取结果集中指定列号或列名的值 |
String getString(int) / String getString(String) | 以字符串方式获取结果集中指定列号或列名的值 |
Object getObject(int)/Object getObject(String) | 以对象方式获取结果集中指定列号或列名的值 |
SQL 注入漏洞
一个有趣的安全漏洞:
//一个简单的登录语句
String sql = format("select * from table where account='%s' and loginPassword='%s';", account, loginPassword);
//假如参数为:
String account = '%(任意)';
String loginPassword = "' or true or '";
这样的情况发生后,参数带入语句结果为:
sql = select * from table where account='%(任意)' and loginPassword='' or true or '';
就发生了 SQL 注入漏洞
PreparedStatement
使用PreparedStatement类解决SQl 注入漏洞
String sql = "select * from Student where stuId=? and login_pwd=?;";
//1.声明时直接传递SQL语句
PreparedStatement statement = connection.prepareStatement(sql);
//2.预编译参数 - 需要在执行语句之前进行预编译
statement.setString(1, account);
statement.setString(2, password);
//3.执行时不再需要SQL语句
ResultSet resultSet = statement.executeQuery();
三、元数据
DatabaseMetaData databaseMetaData = connection.getMetaData();
System.out.println("连接URL:" + databaseMetaData.getURL());
System.out.println("用户名:" + databaseMetaData.getUserName());
System.out.println("连接驱动程序:" + databaseMetaData.getDriverName());
System.out.println("连接驱动版本:" + databaseMetaData.getDriverVersion());
System.out.println("数据库名称:" + databaseMetaData.getDatabaseProductName());
System.out.println("数据库版本:" + databaseMetaData.getDatabaseProductVersion());
System.out.println("数据库中使用的表的类型:");
ResultSet resultSet = databaseMetaData.getTableTypes();
while (resultSet.next()){
System.out.println(resultSet.getString("table_type"));
}
//catalog 表所在数据库名
//schemaPattern 表所在模式名称 null 就搜索所有
//tableNamePattern 要搜索表名的通配符
System.out.println("数据库中的表:");
resultSet = databaseMetaData.getTables("schooldb", null, null, new String[] {"table", "view"});
while (resultSet.next()){
System.out.println(resultSet.getString("table_cat") + "\t" +
resultSet.getString("table_schem") + "\t" +
resultSet.getString("table_name") + "\t" +
resultSet.getString("table_type") + "\t" +
resultSet.getString("remarks")
);
}
Statement statement = connection.createStatement();
ResultSet rs = statement.executeQuery("select * from student");
ResultSetMetaData metaData = rs.getMetaData();
System.out.println("共有" + metaData.getColumnCount() + "列");
for(int i = 1; i <= metaData.getColumnCount(); i++) {
System.out.print("列名:" + metaData.getColumnName(i));
System.out.print("\t是否自增列:" + metaData.isAutoIncrement(i));
System.out.print("\t数据库名:" + metaData.getCatalogName(i));
System.out.print("\t表名:" + metaData.getTableName(i));
System.out.print("\t列类型:" + metaData.getColumnTypeName(i));
System.out.println("\t是否可以为空:" + metaData.isNullable(i));
}