该文章适合初学java web 的朋友,看完了基本能够学会用jdbc操作数据库。
JDBC是什么:
java 数据库连接,java语言操作数据库
JDBC本质:
sun公司提供一个数据库连接的接口,各个数据库公司去实现该接口,并提供jar包(驱动)。我们利用这个接口编程,真正执行的是jar包中的实现类
JDBC连接数据库:
1.将驱动复制粘贴到工程文件目录中,如图
不一定非得是libs文件夹也可以叫别的名字。
jar包下载:MySQL8.0.26版本jar包弄进去后,右键该驱动包点击add as library
连接数据库
这里要确保数据库已经连接好且数据库中有又来操作的表
代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class JdbcDemo1p {
public static void main(String[] args) throws Exception {
//1.注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获取连接对象
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","123456");
//定义sql语句
String sql = "INSERT INTO `db1`.`book`(`书名`, `ISBN`, `价格`, `版本`) VALUES('springboot实战', 'ISBN-9997', '97', '2021')";
//获取执行对象
Statement state = conn.createStatement();
//执行sql
int res = state.executeUpdate(sql);
//打印结果,影响的行数
System.out.println("影响了 "+res+" 行");
//释放资源
state.close();
conn.close();
}
}
运行结果:
说明:这里面的代码下文中会介绍,也可以自己查手册。这里涉及到很多重复代码,下文会把他们封装在一个工具类中。
到这里连接数据库并往数据库中插入一条数据就完成了。(上面暂时没有考虑空指针等问题)
将数据库连接放在一个工具类中
如果不放在工作类中,每次操作都需要来连接数据库,会产生很多重复的代码
连接数据库过程:
1.导入jar包(导入一次就行)
2.注册驱动
3.获取数据库连接对象
4.定义sql语句
5.获取执行sql语句的对象
6.处理结果
7.释放资源
除了6以外,其他的均装在一个类中(6也可以放进去只是,这里没有考虑)。像数据库账号密码和URL可以放在一个配置文件中。
类代码如下:
package util;
import javax.rmi.CORBA.Util;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.sql.*;
import java.util.Properties;
public class JDBCUtils {
//驱动
private static String driver;
//连接对象
private static String url;
//账号
private static String user;
//密码
private static String password;
//不需要实例化对象,所以可以没有构造函数,但是代码需要写在静态代码块中调用
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
static {
//加载配置文件
Properties pro = new Properties();
//获取在src下的配置文件,可以写绝对路径(不容易出问题,但是不方便修改),也可以用ClassLoader加载
ClassLoader classLoader = JDBCUtils.class.getClassLoader();
URL url1 = ClassLoader.getSystemResource("jdbc.properties");
String path = url1.getPath();
//加载配置文件
try {
pro.load(new FileReader(path));
} catch (IOException e) {
e.printStackTrace();
}
//获取配置文件中的值
driver = pro.getProperty("driver");
url = pro.getProperty("url");
user = pro.getProperty("user");
password = pro.getProperty("password");
//注册驱动
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
e.printStackTrace();
}
//
}
//连接对象,需要写在方法中返回连接对象
public static Connection getConnection(String url,String user,String password) throws SQLException {
return DriverManager.getConnection(url,user,password);
}
//释放资源
public static void close(Connection conn, Statement state) {
if (null != conn){
try{
conn.close();
} catch (Exception e){
e.printStackTrace();
}if (null != state){
try{
state.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
//释放资源,重载
public static void close(Connection conn, Statement state, ResultSet res){
if (null != conn)
try {
conn.close();
}catch (Exception e){
e.printStackTrace();
}
if (null != state){
try{
state.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (null != res){
try{
res.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
配置文件:
url=jdbc:mysql:///db1
user=root
password=123456
driver=com.mysql.jdbc.Driver
这样基本就可以用了
先演示一个不用工具类的:
代码:
import domain.Book;
import javax.swing.plaf.nimbus.State;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
/**
*
*将book表封装成对象,放在集合中
*/
public class JdbcDemo6 {
public static void main(String[] args) throws Exception {
List<Book> b = JdbcDemo6.findAll();
for (Book b1:b){
System.out.println(b1);
}
}
public static List<Book> findAll() throws Exception {
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//创建连接
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1","root","123456");
//定义执行sql对象
Statement state = conn.createStatement();
//定义sql语句
String sql = "SELECT * FROM `db1`.`book` LIMIT 0,1000";
//执行sql语句
ResultSet rs = state.executeQuery(sql);
//处理结果
rs.next();
//定义存放数据的容器
List<Book> books = new ArrayList<Book>();
while (rs.next()){
String bookName = rs.getString("书名");
String bookISBN = rs.getString("ISBN");
String bookPrice = rs.getString("价格");
String bookVersion = rs.getString("版本");
Book book = new Book();
book.setBookName(bookName);
book.setBookISBN(bookISBN);
book.setBookPrice(bookPrice);
book.setBookVersion(bookVersion);
books.add(book);
}
//释放资源
if(null !=rs ){
rs.close();
}
if(null !=rs ){
rs.close();
}
if(null !=rs ){
rs.close();
}
return books;
}
}
数据库表:
运行结果:
下面演示用了工具类的:
代码如下:
import domain.Book;
import util.JDBCUtils;
import javax.swing.plaf.nimbus.State;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
*
* 用JDBCUtils工具类操作数据库查询book的信息
*/
public class JdbcDemo7 {
public static void main(String[] args) throws Exception {
//执行这个就已经连好数据库了
Connection conn = JDBCUtils.getConnection();
//定义sql执行对象
Statement state = conn.createStatement();
//定义sql
String sql = "SELECT * FROM `db1`.`book` LIMIT 0,1000";
//执行sql
ResultSet rs = state.executeQuery(sql);
//处理结果
rs.next();
while (rs.next()){
String bookName = rs.getString("书名");
String bookISBN = rs.getString("ISBN");
String bookPrise = rs.getString("价格");
String bookVersion = rs.getString("版本");
Book b = new Book();
b.setBookVersion(bookVersion);
b.setBookPrice(bookPrise);
b.setBookName(bookName);
b.setBookISBN(bookISBN);
System.out.println(b);
}
}
}
相对而言简化了一些,工具类代码和配置文件在上面
上面代码中漏写释放资源的代码了,可以参考上一段没用工具类的代码
执行结果(和上面没用工具类是一样的):
具体例子:实现登录
先创建用户表(这里没有考虑注册和加密问题):
代码:
import util.JDBCUtils;
import javax.swing.*;
import javax.xml.transform.Result;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* 实现用户登录
*/
public class JdbcDemo8 {
public static void main(String[] args) throws Exception {
//连接数据库
Connection conn = JDBCUtils.getConnection();
//定义sql执行对象
Statement state = conn.createStatement();
//定义sql
String sql = "SELECT * FROM `db1`.`user` limit 0,1000";
//执行sql
ResultSet rs = state.executeQuery(sql);
//处理结果
Map<String,String> m = new HashMap();
rs.next();
//将密码保存到HashMap中,因为数据库里面只有一条数据,所以就没用循环
String user = rs.getString("账号");
String password = rs.getString("密码");
m.put(user, password);
//接受用户如输入的账号密码
Scanner in1 = new Scanner(System.in);
System.out.println("请输入账号:");
String userInput = in1.next();
Scanner in2 = new Scanner(System.in);
System.out.println("请输入密码:");
String passwordInput = in2.next();
String checkPassword = new String();
checkPassword = m.get(userInput);
System.out.println("输入的账号"+userInput);
if (checkPassword != null && checkPassword.equals(passwordInput)){
System.out.println("登录成功");
}else{
System.out.println("用户名或者密码错误");
}
if (null !=conn){
conn.close();
}
if (null !=state){
state.close();
}
if (null != rs){
rs.close();
}
}
}
运行结果:
JDBC事务操作(SQL注入,回滚)
SQL注入:静态sql语句如果被拼接就算是错误的输入也能登录
回滚:出现异常时,回到异常前的状态
执行修改前:
发生错误,事务回滚,:
此时虽然执行sql语句,但是没有提交事务,所以数据库中的数据不会发生改变
没有异常的正常情况:
import util.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class JdbcDemo10 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
try {
//1.获取连接
conn = JDBCUtils.getConnection();
//开启事务
conn.setAutoCommit(false);
//2.定义sql
String sql1 = "update book set flag = flag + ? where flag = ?";
//3.获取执行sql对象
pstmt1 = conn.prepareStatement(sql1);
//4. 设置参数
pstmt1.setDouble(1,10);
pstmt1.setInt(2,1);
//5.执行sql
pstmt1.executeUpdate();
// 手动制造异常
// int i = 3/0;
//提交事务
conn.commit();
} catch (Exception e) {
//事务回滚
try {
if(conn != null) {
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}finally {
JDBCUtils.close(conn, pstmt1);
}
}
}
执行结果:
没有发生异常所以没有输出
此时flag已经变成11,这是新加的字段,
注意:不管是否发生异常(是否回滚)都需要释放资源。
说明
个人学习笔记,如果错误感谢指出