文章目录
- 一、Java连接mysql数据库
-
- 1.1 流程
- 1.2 一个测试连接的java程序
- 二、优化:创建一个工具类
-
- 2.1 存在的问题
- 2.2 创建配置文件和工具类
- 2.3 测试使用工具类进行CRUD操作
- 三、SQL注入问题
-
- 3.1 SQL注入示例
- 四、使用PreparedStatement防止SQL注入
- 五、JDBC操作事务
一、Java连接mysql数据库
1.1 流程
java连接mysql大致需要这六步:
-
导入驱动包:这里我使用的是mysql-connector-java-8.0.17.jar(
点击下载
),这个包连接mysql5.6,5.7,8.0版本都没问题。
Class.forName("com.mysql.cj.jdbc.Driver");
-
url和账户名密码
JDBC连接串:jdbc:mysql://:/ -
获取连接:
DriverManager.getConnection(url, user, password);
-
执行sql的Statement对象:
connection.createStatement();
- 执行SQL
- 释放连接
1.2 一个测试连接的java程序
JdbcFirstDemo.java
package com.peng.less01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.导入驱动类
Class.forName("com.mysql.cj.jdbc.Driver");
// 2.用户信息和url
String url = "jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false";
String user = "root";
String password = "12345678";
// 3.获取连接
Connection conn = DriverManager.getConnection(url, user, password);
// 4.执行SQL的对象
Statement sta = conn.createStatement();
// 5.执行SQL
String sql = "select * from account";
ResultSet rs = sta.executeQuery(sql);
while (rs.next()){
System.out.println("id= " + rs.getObject("id"));
System.out.println("name= " + rs.getObject("name"));
System.out.println("money= " + rs.getObject("money"));
System.out.println("=========================================");
}
// 6.释放连接
rs.close();
sta.close();
conn.close();
}
}
这里使用的是VScode,connector包放到了lib目录下,代码放在了src/com/peng/less01下。
执行结果如下,显示了shop.account表下面的三条记录。
二、优化:创建一个工具类
2.1 存在的问题
1、JDBC连接串,用户名,密码等都存在于代码中,需要进行解耦
2、创建连接,释放连接这些操作都是固定的,没必要每次都重复写这些代码(创建函数解决)
2.2 创建配置文件和工具类
src/db.properties 文件中记录driver,url,user,password
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=false
user=root
password=12345678
src/com/peng/less02/utils/JdbcUtils.java 工具类:读取properties配置文件
自动读取配置信息,加载mysql驱动。
package com.peng.less02.utils;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
// 这是一个工具类,用来减少重复操作
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String user = null;
private static String password = null;
static{
try{
// 读取db.properties
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
// 加载驱动
Class.forName(driver);
}catch (Exception e){
e.printStackTrace();
}
}
// 创建连接
public static Connection getConnection() throws SQLException{
return DriverManager.getConnection(url,user,password);
}
// 释放连接
public static void releaseConnection(Connection conn, Statement sta, ResultSet rs){
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (sta != null){
try {
sta.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
2.3 测试使用工具类进行CRUD操作
测试插入操作
src/com/peng/less02/TestInsert.java
package com.peng.less02;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import com.peng.less02.utils.JdbcUtils;
public class TestInsert {
public static void main(String[] args) {
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
sta = conn.createStatement();
String sql = "insert into account(`id`,`name`,`money`) values(4,'药水哥',4698888)";
int i = sta.executeUpdate(sql);
if (i > 0){
System.out.println("插入成功!");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, sta, rs);
}
}
}
测试更新操作
src/com/peng/less02/TestUpdate.java
package com.peng.less02;
import java.sql.*;
import com.peng.less02.utils.JdbcUtils;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
Statement sta = null;
try {
conn = JdbcUtils.getConnection();
sta = conn.createStatement();
String sql = "update account set `money`=238888 where id=3";
int i = sta.executeUpdate(sql);
if (i > 0){
System.out.println("更新成功");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, sta, null);
}
}
}
测试读取操作
package com.peng.less02;
import java.sql.*;
import com.peng.less02.utils.JdbcUtils;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
sta = conn.createStatement();
String sql = "select * from account";
rs = sta.executeQuery(sql);
while (rs.next()){
System.out.println("id= " + rs.getInt("id"));
System.out.println("name= " + rs.getString("name"));
System.out.println("money= " + rs.getObject("money"));
System.out.println("======================================================");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, sta, rs);
}
}
}
三、SQL注入问题
这里写一个登录认证程序,如果账号,密码输入正确则允许登录。为了测试,这里的允许登录改为输出账号密码。
还使用前面写的JdbcUtils工具类
可以看到,这里我输入的用户名/密码是:’ or ‘1=1 ’ or ‘1=1
然后输出了user表中的所有数据,这明显是不合法的。存在sql注入的问题
问题就在于这段代码,sql是拼接而成的。
String sql = "select * from user where `username`='" + username + "' and `password`='" + password + "'";
拼接的sql为:select * from user where `username`='' or '1=1' and `password`='' or '1=1';
3.1 SQL注入示例
SqlInjection.java
package com.peng.less02;
import com.peng.less02.utils.JdbcUtils;
import java.sql.*;
public class SqlInjection {
public static void main(String[] args) {
login("' or '1=1", "' or '1=1");
}
// 登录功能
public static void login(String username, String password){
Connection conn = null;
Statement sta = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
sta = conn.createStatement();
//这段代码中sql是变量拼接而成的
String sql = "select * from user where `username`='" + username + "' and `password`='" + password + "'";
rs = sta.executeQuery(sql);
//输入正确的账号密码就能够登录,这里为了测试就(输入正确输出账号密码)
while (rs.next()){
System.out.println("id= " + rs.getInt("id"));
System.out.println("username= " + rs.getString("username"));
System.out.println("password= " + rs.getObject("password"));
System.out.println("======================================================");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, sta, rs);
}
}
}
四、使用PreparedStatement防止SQL注入
- 使用PreparedStatement,防止SQL注入,同时对于执行多次的SQL更加高效
PreparedStatement,对sql进行了预编译
,传入的参数只会被当作字符串来处理,而不会像前面对sql进行了拼接。
流程如下:
先编写sql –> 进行预编译 –> 增加sql参数值 –> 执行sql
SqlInjection.java
package com.peng.less03;
import com.peng.less02.utils.JdbcUtils;
import java.sql.*;
public class SqlInjection {
public static void main(String[] args) {
// login("'' or 1=1", "'' or 1=1");
login("张三", "zhangsan");
}
// 登录功能
public static void login(String username, String password){
Connection conn = null;
PreparedStatement psta = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
//这里使用 ? 占位符来代替
String sql = "select * from user where `username`=? and `password`=?";
//使用PreparedStatement,防止SQL注入,同时对于执行多次的SQL更加高效
psta = conn.prepareStatement(sql);
psta.setString(1,username);
psta.setObject(2,password);
rs = psta.executeQuery();
//输入正确的账号密码就能够登录,这里为了测试就(输入正确输出账号密码)
while (rs.next()){
System.out.println("id= " + rs.getInt("id"));
System.out.println("username= " + rs.getString("username"));
System.out.println("password= " + rs.getObject("password"));
System.out.println("======================================================");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, psta, rs);
}
}
}
五、JDBC操作事务
和用sql执行事务类似,创建连接后setAutoCommit(false)
,最后commit()
,失败则rollback()
。
注意:rollback()部分可以不用写,事务失败会自动回滚。
TestTransaction.java
package com.peng.less04;
import java.sql.*;
// 仍然使用前面写的JdbcUtils工具类
import com.peng.less02.utils.JdbcUtils;
public class TestTransaction {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pst = null;
try {
conn = JdbcUtils.getConnection();
// 关闭自动提交,开启事务
conn.setAutoCommit(false);
//模拟一个转账事务,A向大帅哥转账100块
String sql1 = "update account set `money`=money - 100 where `name`='A'";
pst = conn.prepareStatement(sql1);
pst.executeUpdate();
// int x = 1/0;
String sql2 = "update account set `money`=money + 100 where `name`='大帅哥'";
conn.prepareStatement(sql2).executeUpdate();
conn.commit();
System.out.println("Success!");
} catch (SQLException e) {
// TODO Auto-generated catch block
try {
// rollback()可以不用写,失败的话会自动回滚
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}finally{
JdbcUtils.releaseConnection(conn, pst, null);
}
}
}