1. 啥是 jdbc ?
jdbc 全称:
java database connection
复制代码
意思就是使用 java 代码连接数据库。
但是问题来了,世界上有一堆数据库例如 mysql、oracle、mongodb 等,他们的使用方法都不太一样。
难道我要连不同的数据库就需要写不同的 java 程序吗?这也太麻烦了。
为了解决这个问题,sun 公司(开发jdk的公司)就决定指定一套接口,这套接口就是使用 java 连接数据库的规范,其实就是 jdbc。
而 jdbc 接口的实现类由数据库厂家负责编写,他们编写后把实现类打包成 jar 包。
这个 jar 包就是一个驱动(例如电脑要连上网需要安装网卡驱动),我们下载好这个驱动后把他放到我们的项目里。
接着编写 java 代码去完善 jar 包要求的连接数据库的信息,然后就能连接到与驱动对应的数据库了。
前面我们在学面向对象的时候知道接口体现了多态性。sun 公司设计一个 jdbc 规范,不用过多关注数据库厂商怎样实现这个接口,大大提高了程序的可扩展性。
2. 导入 jar 包
这里我们以连接 mysql 为例。
- 将连接 mysql 数据库的 jar 包放到 lib 目录下。
注:jar 包就是连接数据库的驱动。每个数据库的厂商将自己实现了 jdbc 的代码打包成 jar 包。
- 将 jar 包作为库添加到项目中。
注:因为 jar 包就是编译后的 java 代码,所以这里就相当于在项目中添加了 java 代码。
选择 lib 目录,右键选择 add as a library。
3. 开发步骤
- 加载数据库的驱动
class.forname("com.mysql.jdbc.driver");
复制代码
注:这里驱动的名字要和数据库的版本对应。
mysql5版本:
class.forname("com.mysql.jdbc.driver");
复制代码
mysql8版本:
class.forname("com.mysql.cj.jdbc.driver");
复制代码
- 创建数据库的连接
// 2. 获得数据库连接
string url = "jdbc:mysql://localhost:3306/course_price";
string user = "root";
string password = "12345678";
connection conn = drivermanager.getconnection(url, user, password);
复制代码
创建数据库的连接需要三个参数:
url,user,password
复制代码
要想连接数据库,第一需要知道数据库是什么类型的数据库,第二需要知道连接的数据库名称吧。所以 url 的格式:
jdbc:数据库类型://localhost:3306/数据库名称
复制代码
有了 url,还需要知道数据库的账号密码。所以有了这三个参数,就能通过 java 程序连接数据库了。
- 测试连接
public static void main(string[] args) {
connection conn = null;
try {
// 1. 加载数据库驱动
class.forname("com.mysql.cj.jdbc.driver");
// 2. 获得数据库连接
string url = "jdbc:mysql://localhost:3306/course_price";
string user = "root";
string password = "12345678";
// 3. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
if(null!=conn){
system.out.println("数据库连接成功");
}else{
system.out.println("数据库连接失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//4、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
测试结果:
注:connection、preparestatement、resultset 都会占用一定的资源,它们需要全部释放/关闭。
- 常见错误
账号或者密码错误
access denied for user 'root'@'localhost' (using password: yes)
复制代码
数据库名称错误
unknown database 'course_pric'
复制代码
url 中数据库类型错误
no suitable driver found for jdbc:mysq://localhost:3306/course_price
复制代码
4. 读取配置文件信息
我们在开发的时候,一般会将连接数据库的信息写到配置文件里面。这样如果连接信息有改变,直接改配置文件里面的信息就行。
4.1 新建 jdbc.properties 文件
url=jdbc:mysql://localhost:3306/course_price
user=root
password=12345678
driver:com.mysql.jdbc.driver
复制代码
4.2 加载配置文件信息
// 1. 加载配置文件
properties pro=new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url=pro.getproperty("url");
string user=pro.getproperty("user");
string password=pro.getproperty("password");
string driver=pro.getproperty("driver");
复制代码
4.3 完整代码
public static void main(string[] args) {
connection conn = null;
try {
// 1. 加载配置文件
properties pro=new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url=pro.getproperty("url");
string user=pro.getproperty("user");
string password=pro.getproperty("password");
string driver=pro.getproperty("driver");
// 3. 加载数据库的驱动
class.forname(driver);
// 4. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
if(null!=conn){
system.out.println("数据库连接成功");
}else{
system.out.println("数据库连接失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//5、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
5. 实现增删改查
5.1 数据库操作对象
连接数据库之后我们就可以使用 java 程序操作数据库,尽情地蹂躏数据库中的数据了。
那怎样操作数据库中的数据呢?其实就是使用 java 程序执行 sql 语句,然后返回执行结果。
我们创建的数据库连接对象 connection 有一个小弟,这小弟叫数据库操作对象,它专门用来执行 sql 语句并返回执行结果。
这个小弟有两种类型:
statement 和 preparestatement。
复制代码
statement 是先进行 sql 语句拼接,再进行 sql 语句的编译,存在sql注入问题。
preparedstatement 是预先编译 sql 语句(带有占位符的sql),然后再给占位符赋值,可以防止 sql 注入。
因为 preparedstatement 效率高并且可以防 sql 注入,所以这里我们使用 preparedstatement 对象进行增删改查。
5.2 查询数据
public static void main(string[] args) {
connection conn = null;
preparedstatement ps = null;
resultset rs = null;
try {
// 1. 加载配置文件
properties pro = new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url = pro.getproperty("url");
string user = pro.getproperty("user");
string password = pro.getproperty("password");
string driver = pro.getproperty("driver");
// 3. 加载数据库的驱动
class.forname(driver);
// 4. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
// 5. sql 语句
string sql = "select * from user";
// 6. 创建执行sql的对象
ps = conn.preparestatement(sql);
// 7. 执行结果
rs = ps.executequery();
while (rs.next()) {
system.out.println("id:" rs.getstring("id"));
system.out.println("name:" rs.getstring("name"));
system.out.println("------");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//8、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (rs != null) {
try {
rs.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
注:
-
- resultset 表示执行的结果
-
- while(resultset.next()) 表示如果执行结果有数据,就一直遍历数据。
执行结果:
5.3 添加数据
public static void main(string[] args) {
connection conn = null;
preparedstatement ps = null;
try {
// 1. 加载配置文件
properties pro = new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url = pro.getproperty("url");
string user = pro.getproperty("user");
string password = pro.getproperty("password");
string driver = pro.getproperty("driver");
// 3. 加载数据库的驱动
class.forname(driver);
// 4. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
// 5. sql 语句
string sql = "insert into user(id,name) values(?,?)";
// 6. 创建执行sql的对象
ps = conn.preparestatement(sql);
// 7. 给 ?赋值
ps.setint(1, 5);
ps.setstring(2, "张无忌");
// 8. 执行sql
int count = ps.executeupdate();
if (count > 0) {
system.out.println("添加成功");
} else {
system.out.println("添加失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//9、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
执行结果:
5.4 修改数据
public static void main(string[] args) {
connection conn = null;
preparedstatement ps = null;
try {
// 1. 加载配置文件
properties pro = new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url = pro.getproperty("url");
string user = pro.getproperty("user");
string password = pro.getproperty("password");
string driver = pro.getproperty("driver");
// 3. 加载数据库的驱动
class.forname(driver);
// 4. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
// 5. sql 语句
string sql = "update user set name = ? where id = ?";
// 6. 创建执行sql的对象
ps = conn.preparestatement(sql);
// 7. 给 ?赋值
ps.setstring(1, "周芷若");
ps.setint(2, 5);
// 8. 执行sql
int count = ps.executeupdate();
if (count > 0) {
system.out.println("修改成功");
} else {
system.out.println("修改失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//9、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
执行结果:
5.5 删除数据
public static void main(string[] args) {
connection conn = null;
preparedstatement ps = null;
try {
// 1. 加载配置文件
properties pro = new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
string url = pro.getproperty("url");
string user = pro.getproperty("user");
string password = pro.getproperty("password");
string driver = pro.getproperty("driver");
// 3. 加载数据库的驱动
class.forname(driver);
// 4. 创建数据库的连接
conn = drivermanager.getconnection(url, user, password);
// 5. sql 语句
string sql = "delete from user where id = ?";
// 6. 创建执行sql的对象
ps = conn.preparestatement(sql);
// 7. 给 ?赋值
ps.setint(1, 4);
// 8. 执行sql
int count = ps.executeupdate();
if (count > 0) {
system.out.println("删除成功");
} else {
system.out.println("删除失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
//9、释放资源
if (conn != null) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (ps != null) {
try {
ps.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
执行结果:
6. 工具类
从上面的例子中,我们发现每次操作都要写一堆连接数据库的信息,操作完还要释放资源,真是烦死了。那能不能简化一下呢?
能,把数据库连接封装成工具类。
我们之前学 static 关键字的时候知道 static 修饰的方法可以直接用类名调用,所以特别适合工具类的使用。
jdbc 工具类:
public class jdbcutils {
private static string user;
private static string password;
private static string url;
private static string driver;
static {
// 静态代码块只需要加载一次,读取资源文件
try {
// 1. 加载配置文件
properties pro = new properties();
pro.load(new filereader("resource/jdbc.properties"));
// 2. 获取配置文件中连接数据库的信息
url = pro.getproperty("url");
user = pro.getproperty("user");
password = pro.getproperty("password");
driver = pro.getproperty("driver");
// 3. 创建数据库连接驱动
class.forname(driver);
} catch (filenotfoundexception e) {
e.printstacktrace();
} catch (ioexception e) {
e.printstacktrace();
} catch (classnotfoundexception e) {
e.printstacktrace();
}
}
// 4. 获取连接对象
public static connection getconnection() throws sqlexception {
return drivermanager.getconnection(url, user, password);
}
// 5. 释放资源
public static void close(preparedstatement ps, connection conn) {
close(null, ps, conn);
}
// 6. 释放资源(重载)
public static void close(resultset rs, preparedstatement ps, connection conn) {
if (null != rs) {
try {
rs.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (null != ps) {
try {
ps.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
if (null != conn) {
try {
conn.close();
} catch (sqlexception e) {
e.printstacktrace();
}
}
}
}
复制代码
有了 jdbc 连接的工具类,代码就可以很清爽,例如:
public static void main(string[] args) {
connection conn = null;
preparedstatement ps = null;
try {
// 1. 获取数据库连接对象
conn = jdbcutils.getconnection();
// 2. sql 语句
string sql = "delete from user where id = ?";
// 3. 创建执行sql的对象
ps = conn.preparestatement(sql);
// 4. 给 ?赋值
ps.setint(1, 4);
// 5. 执行sql
int count = ps.executeupdate();
if (count > 0) {
system.out.println("删除成功");
} else {
system.out.println("删除失败");
}
} catch (exception e) {
e.printstacktrace();
} finally {
// 6. 释放资源
jdbcutils.close(ps, conn);
}
}