一、JDBC概述
1.1 简介
JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。它是一组通用的sql存取与操作的接口API,独立于特定的数据库管理系统,定义了对用来访问数据的类库,可以用来方便的获取数据库资源。简化了程序员的开发细节,为jdbc访问不同的数据库提供了统一的途径。示例图如下:
1.2 结构
jdbc接口API包括两个层次
- 面向数据库的API:Driver API,提供给数据库厂商开发驱动程序
- 面向开发者的API:提供开发人员连接数据库操作数据库等
1.3 jdbc编写步骤流程图
...
二、jdbc获取连接
@Test
public void testConnection() {
try {
//1.数据库连接信息
String url = "jdbc:mysql://localhost:3306/study";
String user = "root";
String password = "123456";
String driverName = "com.mysql.jdbc.Driver";
//2.加载驱动 (①实例化Driver ②注册驱动)
Class.forName(driverName);
//Driver driver = (Driver) clazz.newInstance();
//3.注册驱动
//DriverManager.registerDriver(driver);
/*
可以注释掉上述代码的原因,是因为在mysql的Driver类中声明有:
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
*/
//3.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
System.out.println(conn);
} catch (Exception e) {
e.printStackTrace();
}
}
要点一:Driver接口
- java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
- 在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。
要点二:URL
JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。 JDBC URL的标准由三部分组成,各部分间用冒号分隔。
- jdbc:子协议:子名称
- 协议:JDBC URL中的协议总是jdbc
- 子协议:子协议用于标识一个数据库驱动程序
- 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
- 常见的连接url写法:jdbc:mysql://localhost:3306/study?useUnicode=true&characterEncoding=utf8
三、操作数据库
数据库连接被用于向数据库发送命令和sql,并接受数据库返回的结果。一个数据库连接就是一个Scoket连接。
在java.sql包中定义了三种调用数据库的方式:
- Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。
- PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。
- CallableStatement:用于执行 SQL 存储过程
3.1 Statement
- 1、使用方法:通过Connection对象的createStatement()方法创建该对象
- 2、常用方法:Statement常用方法有两个excuteUpdate(执行更新、插入、删除)、executeQuery(执行查询)
statement虽然可以操作数据库但是却存在弊端,主要有两个问题:一是可能存在sql注入的情况;二是使用Statement操作数据库需要进行字符串拼接,比较繁琐。
sql注入:sql注入是利用系统对用户输入的数据没有充分的检查,导致输入非法数据形成非法的sql语句或者命令。例如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’,通过这个sql即使没有用户名和密码也会返回true。
代码演示
@Test
public void test() throws ClassNotFoundException, SQLException {
//1.加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
Class.forName("com.mysql.cj.jdbc.Driver");
//2.注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序
//我这里使用的驱动版本是8.x,如果在立即注册驱动是会报错误的,Driver类默认会自己注册驱动
// DriverManager.registerDriver(new Driver());
//3.获取数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://xxxxxx:3306/study?useUnicode=true&characterEncoding=utf-8", "root", "xxxxxx");
//4.根据连接获取statement
Statement statement = connection.createStatement();
//5.执行查询sql,sql一般是需要自己拼接的
ResultSet resultSet = statement.executeQuery("select * from user;");
//6.获取结果集的元数据
ResultSetMetaData metaData = resultSet.getMetaData();
//7.获取列数
int columnCount = metaData.getColumnCount();
//8.从结果中取一行数据打印
if (resultSet.next()) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < columnCount; i++) {
String columnName = metaData.getColumnName(i + 1);
Object object = resultSet.getObject(columnName);
sb.append(columnName).append(":").append(object).append("\t");
}
System.out.println(sb);
}
//9.关闭所有连接,我这里为了方便没有try catch异常,建议try catch并把连接关闭写在finally块中保证执行
resultSet.close();
statement.close();
connection.close();
}
3.2 PreparedStatement
PreparedStatement是Statement的一个子接口,表示一条预编译的sql
-
使用方法:通过Connection的PreparedStatement()方法获取该对象,并在获取对象时,可传递一条预编译的sql
-
常用方法:和Statement一样
-
注意点:PrepareStatement可以通过setXXX配置sql,下标从1开始
-
与Statement对比:
- 首先PrepareStatement可以解决Statement出现的SQL注入问题,因为会进行预编译,所以即使有敏感字符也会当做一个字符去处理
- 提高了代码的可读性和维护性,不需要自己拼接sql
- PrepareStatement提高性能,DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。
代码演示
@Test
public void test() throws ClassNotFoundException, SQLException {
//1.加载驱动:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传递要加载的 JDBC 驱动的类名
Class.forName("com.mysql.cj.jdbc.Driver");
//2.注册驱动:DriverManager 类是驱动程序管理器类,负责管理驱动程序
//我这里使用的驱动版本是8.x,如果在立即注册驱动是会报错误的,Driver类默认会自己注册驱动
// DriverManager.registerDriver(new Driver());
//3.获取数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://124.220.191.79:3306/study?useUnicode=true&characterEncoding=utf-8", "root", "1Qaz2wsx@");
//4.根据连接获取statement
PreparedStatement statement = connection.prepareStatement("select * from user where user_name = ?");
//4.1 设置参数
statement.setString(1,"zs");
//5.执行查询sql,sql一般是需要自己拼接的
ResultSet resultSet = statement.executeQuery();
//6.获取结果集的元数据
ResultSetMetaData metaData = resultSet.getMetaData();
//7.获取列数
int columnCount = metaData.getColumnCount();
//8.从结果中取一行数据打印
if (resultSet.next()) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < columnCount; i++) {
String columnName = metaData.getColumnName(i + 1);
Object object = resultSet.getObject(columnName);
sb.append(columnName).append(":").append(object).append("\t");
}
System.out.println(sb);
}
//9.关闭所有连接,我这里为了方便没有try catch异常,建议try catch并把连接关闭写在finally块中保证执行
resultSet.close();
statement.close();
connection.close();
}
3.3 ResultSet
如上述代码演示所示,ResultSet按照逻辑存储查询结果数据表。ResultSet内部维护了一个游标,可以通过next()方法移动游标,next方法是iterator的hashNext()和next()方法的结合,返回结果为boolean类型。初始游标默认停留在数据表第一行,可通过方法getxxx()通过传递列名或者列的下标获取该行数据
3.4 ResultSetMetaData
存储的是结果数据表的元数据信息,记录行的列名、类型、数量等信息,可通过ResultSet对象getMetaData()方法获取该对象
3.5 资源关闭
切记不可忘记关闭资源:ResultSet、Statement、Connection
- 如果资源不关闭,积累多了之后可能导致系统宕机,所以用完之后尽快释放
- 可在finally块中保证资源的最终释放
后续更新...
后续会更新批量插入、数据库连接池等学习记录笔记...