java连接mysql大致需要这六步:
Class.forName("com.mysql.cj.jdbc.Driver");
JDBC连接串:jdbc:mysql://<地址>:<端口>/<数据库>
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表下面的三条记录。
1、JDBC连接串,用户名,密码等都存在于代码中,需要进行解耦
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(); } } } }
测试插入操作
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); } } }
这里写一个登录认证程序,如果账号,密码输入正确则允许登录。为了测试,这里的允许登录改为输出账号密码。
还使用前面写的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';
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进行了预编译,传入的参数只会被当作字符串来处理,而不会像前面对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); } } }
和用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); } } }