首先准备数据库数据,在数据库中进行建表填充数据.
独立抽象方法,重复利用.
第一步,初始化界面(定义一个方法) 第二部,验证用户名,密码(定义另一个方法)
package com.bjpowernode.jdbc; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import java.util.concurrent.CountDownLatch; import com.mysql.*; public class user_login { public static void main(String[] args) { //初始化界面 Map<String, String> userLoginInfoMap=initUI(); //验证用户名和密码 boolean loginSuccess=login(userLoginInfoMap); //输出结果 System.out.println(loginSuccess?"登录成功":"登录失败"); } private static boolean login(Map<String, String> userLoginInfoMap) { //提前打标记 boolean loginsucess=false; String loginName=userLoginInfoMap.get("loginName"); String loginPwd=userLoginInfoMap.get("loginPwd"); Connection conn=null; Statement stmt=null; ResultSet rs=null; try { Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "333"); stmt=conn.createStatement(); String sql="select * from t_user where uname='"+loginName+"' and password='"+loginPwd+"'"; rs=stmt.executeQuery(sql); if(rs.next()) { loginsucess=true; } } catch (Exception e) { e.printStackTrace(); }finally { if(rs!=null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if(stmt!=null) { try { stmt.close(); } catch (Exception e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } } return loginsucess; } /** * 初始化用户界面 * @return 用户输入的用户名和密码等登录信息 */ private static Map<String, String> initUI() { Scanner scanner=new Scanner(System.in); System.out.println("用户名:"); String loginName=scanner.nextLine(); System.out.println("密码:"); String loginPwd=scanner.nextLine(); Map<String, String> userLoginInfoMap=new HashMap<>(); userLoginInfoMap.put("loginName", loginName); userLoginInfoMap.put("loginPwd", loginPwd); return userLoginInfoMap; } }
但是此时当输入
用户名:fdsa
密码:fdsa' or '1'='1
的时候,也会显示登录成功,这种现象称之为 SQL注入 ,黑客经常使用
因为此时sql语句变为:select * from t_user where uname='fdsa' and password='fdsa' or '1'='1' 用户输入的数据参与了sql语句的编译,导致sql语句的原意被扭曲.
如何解决?
Statement有一个子接口,PreparedStatement 预编译的数据库操作对象
它预先对sql语句的框架进行编译,然后只能对sql语句进行传值,而不能修改sql语句的原意.
此时try中的语句这样写,对sql进行预编译处理,便防止了sql注入
Class.forName("com.mysql.jdbc.Driver"); conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode","root","333"); //sql语句的框架,?表示一个占位符,一个占位符将来接收一个"值".注意占位符不能用单引号括起来 String sql="select * from t_user where uname=? and password=?"; //程序执行到此处,会发送sql语句的框架给DBMS,DBMS进行sql语句的预编译 ps=conn.prepareStatement(sql); //给占位符?传值(第一个?下标是1,JDBC中下标从1开始) ps.setString(1, username); ps.setString(2, password); rs=ps.executeQuery(); if(rs.next()) { result=true; }
一般传值情况下使用PreparedStatement,效率高,安全性好.当需要使用到sql注入功能的时候还是要用statement.比如京东上的按照某某升序排序
关于事务
主要语句:
关闭事务自动提交
conn.setAutoCommit(false);
提交事务
conn.commit();
出现异常时事务回滚
该语句可能产生异常,在函数头抛出
conn.rollback();
package JDBC; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class test { public static void main(String[] args) throws SQLException { Connection conn = null; PreparedStatement ps = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/bjpowernode", "root", "333"); // 关闭事务自动提交 conn.setAutoCommit(false); String sql = "update t_act set balance=? where actno=?"; ps = conn.prepareStatement(sql); ps.setDouble(1, 10000); ps.setInt(2, 111); int count = ps.executeUpdate(); ps.setDouble(1, 10000); ps.setInt(2, 222); count += ps.executeUpdate(); System.out.println(count == 2 ? "转账成功" : "转账失败"); // 提交事务 conn.commit(); } catch (Exception e) { // 出现异常时事务回滚 // 该语句可能产生异常,在函数头抛出 conn.rollback(); e.printStackTrace(); } finally { try { if (ps != null) { ps.close(); } } catch (Exception e2) { e2.printStackTrace(); } try { if (conn != null) { conn.close(); } } catch (Exception e2) { e2.printStackTrace(); } } } }