首先准备数据库数据,在数据库中进行建表填充数据.
独立抽象方法,重复利用.
第一步,初始化界面(定义一个方法)
第二部,验证用户名,密码(定义另一个方法)
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();
}
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。