Java - JDBC
JDBC
JDBC简介
为了便于程序保存和读取数据,而且能直接通过条件快速查询大指定的数据,就出现了数据库(Datebase)这种专门用于集中存取和查询的软件。
JDBC是Java程序访问数据库的标准接口。
使用Java程序访问数据库时,Java代码并不是直接通过TCP连接去访问数据库,而是通过JDBC接口来访问数据库的,而JDBC接口则通过JDBC驱动来实现真正对数据库的访问。
JDBC接口是Java标准库自带的,具体的JDBC驱动是由数据库厂商提供的 从代码上来看,JDBC就是定义了一组接口,某个具体的JDBC驱动就是实现这些JDBC接口的类。
MySQL的JDBC驱动就是一个jar包,它本身也是纯Java编写的。我们只需要引入这个JDBC驱动的jar包就可以正常访问MySQL服务器。
我们自己编写的代码只需要引用Java标准库提供的java.sql包下面的相关接口,就可以间接地通过JDBC驱动jar包,通过网络,来访问MySQL服务器了,所有的复杂的网络通讯也都被封装到了JDBC驱动中。
现在Maven的依赖最新版本号是8.0.33。
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
<scope>runtime</scope>
</dependency>
JDBC连接
Connection
Connection代表一个JDBC连接,它相当于Java程序到数据库的连接(通常是TCP连接)。
打开一个Connection时,需要准备URL、用户名和密码,才能成功连接到数据库。
核心代码
核心代码是DriverManager提供的静态方法getConnection()。
DriverManager会自动扫描classpath,找到所有的JDBC驱动,然后根据我们传入的URL自动挑选一个合适的驱动。
因为JDBC连接是一种昂贵的资源,所以使用后要及时释放,所以使用try (resource)来自动释放。
class Main{
public static void main(String[] args) throws SQLException {
String JDBC_URL = "jdbc:mysql://localhost:3306/learnjdbc?useSSL=false&serverTimezone=UTC";//要连接已创建的数据库,我这个test数据库是已经创建好的。
String JDBC_USER = "root";//root是默认的超级用户
String JDBC_PASSWORD = "11111111";//自定义密码,千万设置完别忘了
Connection conn = null;
try {
// 获取连接
conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
System.out.println("连接成功!");
// TODO: 访问数据库...
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
JDBC查询
代码步骤:
1.通过Connection提供的createStatement()方法创建一个Statement对象,用于执行一个查询;
2.执行Statement对象提供的executeQuery("SELECT * FROM students")并传入SQL语句,执行查询并获得返回的结果集,使用ResultSet来引用这个结果集;
3.反复调用ResultSet的next()方法并读取每一行结果。
注意:
因为Connection、Statement、ResultSet都是许哟啊关闭的资源,所以需要嵌套使用try,确保即时关闭,所以显得繁琐。
ResultSet获取列时,是从1开始的。
ResultSet获取列时,必须根据select的列对应的位置调用getLong()、getString()这些方法,否则对应位置的数据类型不对,将报错。
Connection conn = null;
try {
// 获取连接
conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
System.out.println("连接成功!");
// TODO: 访问数据库...
Statement statement=null;
try {
statement = conn.createStatement();
ResultSet result=null;
try {
result = statement.executeQuery("select * from students");
while (result.next()){
long id=result.getLong(1);
String name=result.getString(2);
long gender=result.getLong(3);
long grade=result.getLong(4);
int score=result.getInt(5);
System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);
}
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (result!=null)
try {
result.close();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (RuntimeException e) {
throw new RuntimeException(e);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭连接
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
SQL注入
为了避免SQL注入攻击,和statement拼接字符串非常容易引发SQL注入问题。
所以使用Java对数据库进行操作时,必须使用PreparedStatement,严禁任何通过参数拼字符串的代码!!!!
// TODO: 访问数据库...
PreparedStatement ps=null;
ps = conn.prepareStatement("select * from students where id>? and score>=?");
ps.setObject(1,2);
ps.setObject(2,60);
ResultSet result=null;
result=ps.executeQuery();
while (result.next()){
long id=result.getLong(1);
String name=result.getString(2);
long gender=result.getLong(3);
long grade=result.getLong(4);
int score=result.getInt(5);
System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);
}
数据类型
使用JDBC的时候,我们需要在Java数据类型和SQL数据类型之间进行转换。 JDBC在java.sql.Types定义了一组常量来表示如何映射SQL数据类型。
JDBC的增删改查
查
// TODO: 访问数据库...
PreparedStatement ps=null;
ps = conn.prepareStatement("select * from students where id>? and score>=?");
ps.setObject(1,2);
ps.setObject(2,60);
ResultSet result=null;
result=ps.executeQuery();
while (result.next()){
long id=result.getLong(1);
String name=result.getString(2);
long gender=result.getLong(3);
long grade=result.getLong(4);
int score=result.getInt(5);
System.out.println(id+" "+name+" "+gender+" "+grade+" "+score);
}
增
// TODO: 访问数据库...
PreparedStatement ps=null;
ps=conn.prepareStatement("INSERT INTO students (grade, name, gender,score) VALUES (?,?,?,?)",Statement.RETURN_GENERATED_KEYS);
ps.setObject(1, 1); // grade
ps.setObject(2, "olderhard"); // name
ps.setObject(3, 1); // gender
ps.setObject(4, 90); // score
int n = ps.executeUpdate();
ResultSet result=null;
result=ps.getGeneratedKeys();
if (result.next()){
System.out.println(result.getLong(1));
}
改
// TODO: 访问数据库...
PreparedStatement ps=null;
ps=conn.prepareStatement("UPDATE students SET name=? WHERE id=?");
ps.setObject(1,"bob");
ps.setObject(2,14);
iint n=ps.executeUpdate();
删
// TODO: 访问数据库...
PreparedStatement ps=null;
ps=conn.prepareStatement("DELETE FROM students WHERE id=?");
ps.setObject(1,15);
int n=ps.executeUpdate();
JDBC事务
数据库事务时由若干个SQL语句构成的一个操作序列。数据库系统保证在一个事务中所有SQL要么全部执行成功,要么全部不执行,即数据库事务具有ACID特性,原子性,一致性,隔离性,持久性。
要在JDBC中执行事务,本质上就是如何把多条SQL包裹在一个数据库事务中执行。
注意关键点即可:连接成功后;conn.setAutoCommit(false);之后对数据库操作完成后;就conn.commit(),提交事务;再加一个异常回滚conn.rollback()。
Connection conn = null;
PreparedStatement p1=null;
PreparedStatement p2=null;
try {
// 获取连接
conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
System.out.println("连接成功!");
conn.setAutoCommit(false); //关闭自动提交模式
// TODO: 一系列对数据库的操作...
conn.commit(); //提交事务
} catch (SQLException e) {
if(conn!=null){
try {
conn.rollback();
System.out.println("Transaction rolled back.");
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
}
JDBC批处理
在JDBC代码中,我们可以利用SQL数据库的特性,把同一个SQL但参数不同的若干次操作合并为一个batch执行。
使用JDBC的batch操作会大大提高执行效率,对内容相同,参数不同的SQL,要优先考虑batch操作。
// TODO: 访问数据库...
PreparedStatement ps=null;
ps=conn.prepareStatement("INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)");
for (Student s : students) {
ps.setString(1, s.name);
ps.setBoolean(2, s.gender);
ps.setInt(3, s.grade);
ps.setInt(4, s.score);
ps.addBatch(); // 添加到batch
}
// 执行batch:
int[] ns = ps.executeBatch();
for (int n : ns) {
System.out.println(n + " inserted."); // batch中每个SQL执行的结果数量
}
JDBC连接池
与多线程的线程池原因类似,在执行JDBC的增删改查的操作时,如果每一次操作都来一次打开连接,操作,关闭连接。那么创建和销毁JDBC连接的开销就太大了。为了避免频繁地创建和销毁JDBC连接,我们可以通过连接池复用已经创建好的连接。
JDBC连接池有一个标准的接口javax.sql.DataSource,要使用JDBC连接池,我们必须选择一个JDBC连接池的实现。
常用的JDBC连接池有:HikariCP、C3P0、BoneCP、Druid
之后我们通过创建一个DATa Source实例(对象),这个就是连接池。
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
config.setUsername("root");
config.setPassword("password");
config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒
config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒
config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10
DataSource ds = new HikariDataSource(config);
如何使用连接池?
类似这个
conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD);
这样使用
conn = config.getConnection();
原文地址:https://blog.csdn.net/m0_74403543/article/details/142705633
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!