一、什么是JDBC
JDBC的全称是Java数据库连接(Java Database Connectivity),它是一套用于执行SQL语句的Java API。应用程序可通过这套API连接到关系型数据库,并使用SQL语句完成对数据库中数据的新增、删除、修改和查询等操作。
二、JDBC常用API
在开发JDBC程序前,先了解一下JDBC常用的API。JDBC API主要位于java.sql包中,该包定义了一系列访问数据库的接口和类。
(1)Driver接口
Driver接口是所有JDBC驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。需要注意的是,在编写JDBC程序时,必须要把所使用的数据库驱动程序或类库加载到项目的classpath中(这里指MySQL驱动JAR包)。
(2)DriverManager接口
DriverManager接口用于加载JDBC驱动、创建与数据库的连接。在DriverManager接口中,定义了两个比较重要的静态方法.
(3)Connection接口
Connection接口用于处理与特定数据库的连接,Connection对象是表示数据库连接的对象,只有获得该连接对象,才能访问并操作数据库。
(4)Statement接口
Statement接口用于执行静态的SQL语句,并返回一个结果对象。Statement接口对象可以通过Connection实例的createStatement()方法获得,该对象会把静态的SQL语句发送到数据库中编译执行,然后返回数据库的处理结果。
(5)PreparedStatement 接口
Statement接口封装了JDBC执行SQL语句的方法,可以完成Java程序执行SQL语句的操作。然而在实际开发过程中往往需要将程序中的变量作为SQL语句的查询条件,而使用Statement接口操作这些SQL语句会过于繁琐,并且存在安全方面的问题。针对这一问题,JDBC API 提供了扩展的PreparedStatement接口。
PreparedStatement是Statement的子接口,用于执行预编译的SQL语句。PreparedStatement接口扩展了带有参数SQL语句的执行操作,该接口中的SQL语句可以使用占位符“?”代替参数,然后通过setter()方法为SQL语句的参数赋值。
(6)ResultSet接口
ResultSet接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(或指针),ResultSet对象初始化时,游标在表格的第一行之前,调用next()方法可以将游标移动到下一行。如果下一行没有数据,则返回false。在应用程序中经常使用next()方法作为while循环的条件来迭代ResultSet结果集。
程序既可以通过字段的名称来获取指定数据,也可以通过字段的索引来获取指定的数据,字段的索引是从1开始编号的。
三、实现JDBC
第一步,加载并注册数据库驱动
两种方式
第一种,java.lang.Class类的静态方法forName(String className)
Class.forName("DriverName");
第二种,DriverManager类的静态方法registerDriver(Driver driver)
DriverManager.registerDriver(Driver driver);
实际开发中常用第一种,DriverName表示数据库的驱动类。例如在mysql中,MySQL驱动类在6.0.2版本之前为com.mysql.jdbc.Driver,而在6.0.2版本之后为com.mysql.cj.jdbc.Driver。
第二步 ,通过DriverManager获取数据库连接
获取数据库连接的具体方式
Connection conn = DriverManager.getConnection(String url, String user, String pwd);
以上三个参数分别表示连接数据库的地址、登录数据库的用户名和密码。
eg:jdbc:mysql://hostname:port/databasename
如果是在高版本mysql中以上格式会报错,只需要改为:
url=jdbc:mysql://127.0.0.1:3306/jdbc?characterEncoding=utf8&useSSL=true 即可
jdbc:mysql:是固定的写法,mysql指的是MySQL数据库,hostname指的是主机的名称,port指的是连接数据库的端口号(MySQL端口号默认为3306),databasename指的是MySQL中相应数据库的名称。
第三步,通过第二步中的Connection对象获取Statement对象
Connection创建Statement对象的方法有3个(预处理对象):
createStatement():创建基本的Statement对象。
prepareStatement():创建PreparedStatement对象(主要)
repareCall():创建CallableStatement对象
第四步,使用Statement执行SQL语句
所有的Statement都有3种执行SQL语句的方法:
execute():可以执行任何SQL语句,返回布尔值
executeQuery():通常执行查询语句,执行后返回代表结果集的ResultSet对象。
executeUpdate():主要用于执行DML和DDL语句。执行DML语句,如INSERT、UPDATE或DELETE时,返回受SQL语句影响的行数。
第五步,操作ResultSet结果集
如果是查询语句,执行结果将返回一个ResultSet对象。该对象保存了SQL语句查询的结果。程序可以通过操作该ResultSet对象取出查询结果。
next()向下移动一行,同时如果没有下一行,返回false
previous()向上移动一行,如果没有上一行,返回false
getxxx(列的索引 || 列名),返回对应列的值,接收的类型和xxx一样
getObject(列的索引 || 列名),返回对应列的值,接收的类型为Object
第六步,关闭连接,释放资源
每次操作数据库结束后都要关闭数据库连接,释放资源,关闭顺序和声明顺序相反。需要关闭的资源包括ResultSet、Statement和Connection等。
注意:
在后续可以不必显式注册驱动。因为在DriverManager的源码中已经存在静态代码块,实现了驱动的注册。
代码
前置环境,需要有数据库,创建表数据。在项目中添加相关的依赖。
public class example01 {
public static void main(String[] args) throws Exception {
Connection conn = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1.注册数据库驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取数据库连接
String url = "jdbc:mysql://localhost:3306/mydb";
String root = "root";
String password = "123456";
conn = DriverManager.getConnection(url, root, password);
//3.获取Statement对象
statement = conn.createStatement();
//4.使用Statement执行SQl语句
String sql = "select * from user";
resultSet = statement.executeQuery(sql);
//5.操作ResultSet结果集
while (resultSet.next()) {
int id = resultSet.getInt("id");// 通过列名获取指定字段的值
String name = resultSet.getString("username");
String password1 = resultSet.getString("password");
System.out.println(id + " | " + name + " | " + password1);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
四、使用JDBC实现增删改查的基本操作
以上为正常的数据库连接,接下来使用便捷的方法。
创建一个properties的文件,文件输入相应的配置信息。
将JDBC操作的连接,关闭封装到一个类中,使用时调用相对应的方法。
使用PreparedStatement进行操作:
PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的SQL语句
PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数。setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值。
public class JDBCUtils{
/**
* 数据库连接
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception{
//1.读取配置文件的4个基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//2.加载驱动
Class.forName(driverClass);
//3.获取连接
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
/**
* 数据库资源关闭
* @param conn
* @param ps
* @param rs
*/
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
try {
if (ps != null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(rs != null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
@Test
public void test() throws Exception {
Com com = new Com();
String sql = "update user set password = ? where id = ? ";
com.update(sql,123456 ,1);
}
getColumnName(int column):获取指定列的名称
getColumnLabel(int column):获取指定列的别名
getColumnCount():返回当前 ResultSet 对象中的列数。
getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
isNullable(int column):指示指定列中的值是否可以为 null。
isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。
Java与数据库交互涉及到的相关Java API中的索引都从1开始。
/**
* 针对不同数据表的查询操作
* @param clazz
* @param sql
* @param args
* @return
* @param <T>
*/
public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
// 1.获取数据库连接
conn = JDBCUtils.getConnection();
// 2.预编译sql语句,得到PreparedStatement对象
ps = conn.prepareStatement(sql);
// 3.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 4.执行executeQuery(),得到结果集:
ResultSet resultSet = ps.executeQuery();
// 5.得到结果集的元数据:ResultSetMetaData
ResultSetMetaData rsmd = resultSet.getMetaData();
// 6.1通过ResultSetMetaData得到columnCount,columnLabel;通过ResultSet得到列值
int columnCount = rsmd.getColumnCount();
if (resultSet.next()) {
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//获取列值
Object columnVal = resultSet.getObject(i + 1);
// 获取列的别名:列的别名,使用类的属性名充当
String columnLabel = rsmd.getColumnLabel(i + 1);
// 6.2使用反射,给对象的相应属性赋值 记得有对应的类以及属性
Field field = clazz.getDeclaredField(columnLabel);
field.setAccessible(true);
field.set(t, columnVal);
}
return t;
}
} catch (Exception e) {
e.printStackTrace();
} finally { // 7.关闭资源
JDBCUtils.closeResource(conn, ps, rs);
}
return null;
}