JDBC
JDBC(Java DataBase Connectivity)是Java和数据库之间的一个桥梁,是一个规范而不是一个实现,能够执行SQL语句。它由一组用Java语言编写的类和接口组成。各种不同类型的数据库都有相应的实现
JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
执行流程:
- 连接数据源,如:数据库。
- 为数据库传递查询和更新指令。
- 处理数据库响应并返回的结果
JDBC具体语法1:
1.获取连接对象
// 参数为连接数据名,用户名,密码(这里密码为空妹设密码)
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3","root","");
2.创建SQL执行对象Statement
Statement s = conn.createStatement();
3.执行SQL语句
String sql = "create table jdbct1(id int,name varchar(10))";
s.execute(sql);
4.关闭连接
conn.close();
JDBC具体语法2(创建预编译SQL执行对象):
2.创建预编译SQL执行对象PreparedStatement
// 此sql语句用?号进行占位
String sql = "select count(*) from user where username=? and password=?";
// 创建预编译的SQL执行对象
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, name); // 第一个?是name(不是从0开始的!)
ps.setString(2, pwd); // 第二个?是pwd
3.执行SQL语句
// 这里()里面就不需要再写sql了
ResultSet rs = ps.executeQuery();
预编译SQL执行对象PreparedStatement相比较Statement的优势
-
代码整洁
-
可以避免SQL注入风险,因为在创建对象时已经把SQL语句的逻辑锁死,不会被用户输入的内容所影响
-
如果SQL语句中没有使用变量则使用Statement,如果有变量则使用PreparedStatement
示例:
- 创建maven工程,在pom.xml中导入jar包
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
- 增删改查基本操作如下
public void test() throws SQLException {
System.out.println("执行sql语句");
// 获取连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",columnIndex
""
);
// 创建SQL执行对象
Statement s = conn.createStatement();
// 执行SQL插入语句
String sql = "insert into jdbct1 values(1,'张三'),(2,'李四'),(3,'王五'),(4,'周六')";
s.executeUpdate(sql);
// 执行SQL修改语句
sql = "update jdbct1 set name='张三三' where id=1";
s.executeUpdate(sql);
// 执行SQL删除语句
sql = "delete from jdbct1 where id=1";
s.executeUpdate(sql);
// 执行SQL查询语句
sql = "select * from jdbct1";
// 查询得到一个ResultSet结果集
ResultSet rs = s.executeQuery(sql);
System.out.println(rs.getFetchSize());
// 遍历结果集
while(rs.next()) {
int id = rs.getInt("id");
// 这里还可以写数字,代表获取的第几个字段
String name = rs.getString("name");
System.out.println(id+":"+name);
}
// 关闭连接
conn.close();
System.out.println("执行完成!");
}
执行SQL的查询语句得到的是一个ResultSet查询结果集
- 可通过遍历ResultSet得到每一个查询出来的值
- rs.next()判断是否还有下一个
- rs.getString/rs.getInt等方法得到字段的值
DBCP数据库连接池
- DBCP:DataBase Connection Pool
- 作用:将连接重用,避免频繁的开关连接,从而达到提高执行效率的目的
package cn.tedu.jdbc;
import java.sql.Connection;
import java.sql.SQLException;
import org.apache.commons.dbcp.BasicDataSource;
/**
* 数据库连接池
*/
public class Demo_03 {
public static void main(String[] args) throws SQLException {
// 创建数据库连接池对象
BasicDataSource ds = new BasicDataSource();
// 设置连接信息
// 注册驱动 告诉编译器使用的数据库是MySQL
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/newdb3");
ds.setUsername("root");
ds.setPassword("");
// 设置初始连接对象
ds.setInitialSize(3);
// 设置最大连接数量
ds.setMaxActive(5);
// 从连接池中获取连接对象
Connection conn = ds.getConnection();
System.out.println(conn);
}
}
需要在pom.xml中导入相应jar包,maven 仓库中搜索dbcp
<!-- 数据库连接池坐标 -->
<!-- https://mvnrepository.com/artifact/commons-dbcp/commons-dbcp -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.3</version>
</dependency>
将数据库连接池/连接对象写在一个工具类DBUtils.java中
-
在src/main/resources下新建配置文件jdbc.properties,将数据库连接相关的信息写入此文件中
# Database config # 注册驱动 driver = com.mysql.jdbc.Driver # 数据库路径 url = jdbc:mysql://localhost:3306/newdb3 # 用户名 username = root # 密码(此处没有密码,注意:不能写成空字符串 password=""是错的) password =
- 将数据库连接对象写在工具类DBUtils.java中
package cn.tedu.jdbc; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.Properties; import org.apache.commons.dbcp.BasicDataSource; /** * 数据库操作的工具类 */ public class DBUtils { private static BasicDataSource ds; static { // 创建属性对象 Properties p = new Properties(); // 获取文件输入流 InputStream ips = DBUtils.class.getClassLoader().getResourceAsStream("jdbc.properties"); // 把文件加载到属性对象中 try { p.load(ips); } catch (IOException e) { e.printStackTrace(); } // 连接数据库的相关信息 String driver = p.getProperty("driver"); String url = p.getProperty("url"); String username = p.getProperty("username"); String password = p.getProperty("password"); // 创建数据库连接池对象 ds = new BasicDataSource(); // 设置连接信息 // 注册驱动 告诉编译器使用的数据库是MySQL ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); // 设置初始连接对象 ds.setInitialSize(3); // 设置最大连接数量 ds.setMaxActive(5); } /** * 获取连接对象Connection * @return conn * @throws Exception */ public static Connection getConn() throws Exception { // 从连接池中获取连接对象 Connection conn = ds.getConnection(); return conn; } }
批量操作
将多条SQL语句由默认的多次数据传输合并成一次传输,从而提高执行效率。
Statement对象
- 创建SQL执行对象
Statement s = conn.createStatement(); - 添加到批量操作
s.addBatch(sql1);
s.addBatch(sql2);
s.addBatch(sql3); - 执行批量操作(这样网络只传输一次,如果分三次执行的话网络传输三次)
s.executeBatch();
PreparedStatement对象
- 创建SQL执行对象
PreparedStatement ps = conn.prepareStatement(sql); - 添加到批量操作
ps.addBatch(); - 执行批量操作
ps.executeBatch();
示例:
package cn.tedu.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.Statement;
import org.junit.Test;
public class Demo_05 {
@Test
/**
* 批量插入示例(Statement对象)
*/
public void test01() {
try (Connection conn = DBUtils.getConn()) {
String sql1 = "insert into jdbct1 values(6,'璐璐')";
String sql2 = "insert into jdbct1 values(7,'七七')";
String sql3 = "insert into jdbct1 values(8,'巴巴')";
// 创建SQL执行对象
Statement s = conn.createStatement();
// 添加到批量操作
s.addBatch(sql1);
s.addBatch(sql2);
s.addBatch(sql3);
// 执行批量操作(这样网络只传输一次,如果分三次执行的话网络传输三次)
s.executeBatch();
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
/**
* 往数据库中插入100条数据(PreparedStatement对象)
* user表字段(id,username,password)
*/
public void test02() {
try (Connection conn = DBUtils.getConn()) {
String sql = "insert into user values(null,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for(int i=1;i<=100;i++) {
ps.setString(1, "name"+i);
ps.setString(2, "pwd"+i);
// 添加到批量操作
ps.addBatch();
// 避免内存溢出(每隔20条执行一次)
if(i%20==0) {
// 执行批量操作
ps.executeBatch();
}
}
// 执行批量操作
ps.executeBatch();
System.out.println("执行完毕!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
获取自增主键值
如果插入数据后需要使用自增的主键值时用以下代码
-
创建SQL执行对象 并设置获取自增主键值(传入第二个参数Statement.RETURN_GENERATED_KEYS)
PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); -
获取自增主键值(返回ResultSet)
ResultSet rs = ps.getGeneratedKeys();
遍历后:int id = rs.getInt(1);
返回的结果只有一个id,固定写法package cn.tedu.jdbc; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; public class Demo_07 { public static void main(String[] args) { try (Connection conn = DBUtils.getConn()) { String name = "Tom"; String pwd = "123"; String sql = "insert into user values(null,?,?)"; // 创建SQL执行对象 并设置获取自增主键值 PreparedStatement ps = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS); ps.setString(1, name); ps.setString(2, pwd); ps.executeUpdate(); // 获取自增主键值 ResultSet rs = ps.getGeneratedKeys(); while(rs.next()) { // 获取自增的id int id = rs.getInt(1); System.out.println("id="+id); } } catch (Exception e) { e.printStackTrace(); } } }
数据库元数据对象
数据库的元数据对象,该对象保存了数据库的相关信息
- 获取数据库元对象
- DatabaseMetaData dbmd = conn.getMetaData();//获取元数据对象
- dbmd.getDatabaseProductName() 获取数据库名
- dbmd.getDriverVersion() 获取数据库的驱动版本
- dbmd.getUserName() 获取数据库的用户名
- 获取表元数据对象(需要先写查询)
- ResultSet rs = s.executeQuery(sql);
- ResultSetMetaData rsmd = rs.getMetaData(); 获取表元数据对象
- int count = rsmd.getColumnCount(); 获取字段数量
- rsmd.getColumnName(int i); 获取字段名称
- rsmd.getColumnTypeName(i+1); 获取字段类型
相应的方法有很多,这里只列举常用的几个,其他的用到的时候去查API
示例:
package cn.demo.jdbc;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
/**
* 数据库元对象,该对象保存了数据相关的信息
*/
public class Demo_08 {
public static void main(String[] args) {
try (Connection conn = DBUtils.getConn()) {
// 获取数据库元数据对象
DatabaseMetaData dbmd = conn.getMetaData();
System.out.println("数据库名:"+dbmd.getDatabaseProductName());
System.out.println("数据库驱动版本:"+dbmd.getDriverVersion());
System.out.println("数据库用户名:"+dbmd.getUserName());
// 获取表元数据对象需要先写查询
String sql = "select * from emp";
Statement s = conn.createStatement();
ResultSet rs = s.executeQuery(sql);
// 获取表元数据对象
ResultSetMetaData rsmd = rs.getMetaData();
// 获取字段数量
int count = rsmd.getColumnCount();
// 遍历每个字段的信息
for(int i=0;i<count;i++) {
String name = rsmd.getColumnName(i+1);
String type = rsmd.getColumnTypeName(i+1);
System.out.println(name+":"+type);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 打印结果如下:
数据库名:MySQL
数据库驱动版本:mysql-connector-java-5.1.6 ( Revision: ${svn.Revision} )
数据库用户名:root@localhost
EMPNO:INT
ENAME:VARCHAR
JOB:VARCHAR
MGR:INT
HIREdate:DATE
SAL:DOUBLE
COMM:DOUBLE
DEPTNO:INT