JDBC
- java.sql.*
编程六步
- 注册驱动
- 获取连接属于(属于进程间的通信,使用后一定要关闭)
- 获取数据库操作对象
- 执行SQL语句
- 处理查询结果集(只有第四步执行是select语句,才需要处理)
- 释放资源
package Sql;
import java.sql.*;
import java.util.ResourceBundle;
public class Test01 {
public static void main (String[] args) throws SQLException {
//获取配置文件信息
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String url = bundle .getString("url") ;
String user = bundle .getString("user") ;
String password = bundle .getString ("password") ;
Connection conn = null;
Statement stmt = null;
try {
//1. 注册驱动
Class.forName(driver);
//2. 获取连接属于(属于进程间的通信,使用后一定要关闭)
conn = DriverManager.getConnection(url, user, password);
//3. 获取数据库操作对象
stmt = conn.createStatement();
//4. 执行SQL语句
String sql = "update beauty set name = 132 where id =1;";
int count = stmt.executeUpdate(sql);
System.out.println(count == 1? "修改成功":"修改失败");
//5. 处理查询结果集(只有第四步执行是select语句,才需要处理)
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
//6. 释放资源
if (stmt != null){
stmt.close();
}
if (conn != null){
conn.close();
}
}
}
}
处理查询结果
- int eccuteUpdate(String sql); 可传入insert,delate,update 返回增删减了多少行数据
- ResultSet excuteQuery(String sql); 专门执行select语句
返回ResultSet对象
JDBC数据,是从1开始
ResultSet对象常用方法
-
boolean next()
throws SQLException
将光标从当前位置向前移一行。 ResultSet 光标最初位于第一行之前;第一次调用 next 方法使第一行成为当前行;第二次调用使第二行成为当前行,依此类推。 -
String getString(int columnIndex)
//当使用列名查询时,列名是查询结果集的列名称
throws SQLException
以 Java 编程语言中 String 的形式获取此 ResultSet 对象的当前行中指定列的值。 -
boolean wasNull()
throws SQLException
报告最后一个读取的列是否具有值 SQL NULL。注意,必须首先对列调用一个获取方法尝试读取其值,然后调用 wasNull 方法查看读取的值是否为 SQL NULL。 -
getInt
int getInt(int columnIndex)
throws SQLException
以 Java 编程语言中 int 的形式获取此 ResultSet 对象的当前行中指定列的值。
package Sql;
import java.sql.*;
import java.util.ResourceBundle;
public class Test01 {
public static void main (String[] args) throws SQLException {
//获取配置文件信息
ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
String driver = bundle.getString("driver");
String url = bundle .getString("url") ;
String user = bundle .getString("user") ;
String password = bundle .getString ("password") ;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1. 注册驱动
Class.forName(driver);
//2. 获取连接属于(属于进程间的通信,使用后一定要关闭)
conn = DriverManager.getConnection(url, user, password);
//3. 获取数据库操作对象
stmt = conn.createStatement();
//4. 执行SQL语句
String sql = "select * from beauty;";
rs = stmt.executeQuery(sql);
//5. 处理查询结果集(只有第四步执行是select语句,才需要处理)
boolean flag1 = rs.next();
if (flag1){
/*
String id = rs.getString(1);
String name = rs.getString(2);
String sex = rs.getString(3);
*/
String id = rs.getString("id");
String name = rs.getString("name");
String sex = rs.getString("sex");
System.out.println(id + name + sex);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
//6. 释放资源
if (rs != null){
rs.close();
}
if (stmt != null){
stmt.close();
}
if (conn != null){
conn.close();
}
}
}
}
SQL注入
package Sql;
/*
实现功能:
1、需求:模拟用户登录功能的实现。,
2、业务描述:
程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
用户输入用户名和密码之后,提交信息,java程序收集到用户信息
Java程序连接数据库验证用户名和密码是否合法
合法:显示登录成功
不合法:显示登录失败
3、数据准备
建模工具:PowerDesigner
4、sql注入
导致sQL注入的根本原因是什么?
用户输入的信息中含有 sq1语句的关键字,并且这些关键字参与sq1语句的编译过程,
导致sq1语句的原意被扭曲,进而达到sql注入。
*/
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
public class UserTest {
public static void main (String[] args){
//初始化一个界面
Map<String,String>userLoginInfo = initUI();
//验证用户名
boolean loginSuccess = login(userLoginInfo);
//输出结果
System.out.println(loginSuccess?"登陆成功":"登陆失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
String loginName = userLoginInfo.get("loginName");
String loginPwd = userLoginInfo.get("loginPwd");
//JDBC代码
ResourceBundle bundle = ResourceBundle.getBundle("user");
String driver = bundle.getString("driver");
String url = bundle .getString("url") ;
String user = bundle .getString("user") ;
String password = bundle .getString ("password") ;
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
//1. 注册驱动
Class.forName(driver);
//2. 获取连接属于(属于进程间的通信,使用后一定要关闭)
conn = DriverManager.getConnection(url, user, password);
//3. 获取数据库操作对象
stmt = conn.createStatement();
//4. 执行SQL语句
String sql = "select * from user where username = '"+loginName+"'" +
"and userPwd = '"+loginPwd+"';";
rs = stmt.executeQuery(sql);
//5. 处理查询结果集(只有第四步执行是select语句,才需要处理)
if (rs.next()){
//登陆成功
loginSuccess = true;
}else {
loginSuccess = false;
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
finally {
//6. 释放资源
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
/**
* 初始化界面
* @return
*/
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.println("欢迎登陆");
System.out.print("用户名:");
String loginName = s.nextLine();
System.out.print("用户密码:");
String loginPwd = s.nextLine();
Map<String,String> userloginInfo = new HashMap<>();
userloginInfo.put("loginName", loginName);
userloginInfo.put("loginPwd", loginPwd);
return userloginInfo;
}
}
使用preparedstatement
package Sql;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
/*
* 解决sql注入问题
* 只要用户提供过的信息不参与sql语句的编译过程,问题就解决了
* 只要用户提供的信息含有sql语句的关键字,但没参与编译,不起作用
* java.sql.PreparedStatement预编译数据库操作对象,
* 预先对sql语句框架进行编译,然后再给sql语句传值
* */
public class userTest02 {
public static void main (String[] args){
//初始化一个界面
Map<String,String> userLoginInfo = initUI();
//验证用户名
boolean loginSuccess = login(userLoginInfo);
//输出结果
System.out.println(loginSuccess?"登陆成功":"登陆失败");
}
private static boolean login(Map<String, String> userLoginInfo) {
boolean loginSuccess = false;
String loginName = userLoginInfo.get("loginName");
String loginPwd = userLoginInfo.get("loginPwd");
//JDBC代码
ResourceBundle bundle = ResourceBundle.getBundle("user");
String driver = bundle.getString("driver");
String url = bundle .getString("url") ;
String user = bundle .getString("user") ;
String password = bundle .getString ("password") ;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1. 注册驱动
Class.forName(driver);
//2. 获取连接属于(属于进程间的通信,使用后一定要关闭)
conn = DriverManager.getConnection(url, user, password);
//3. 获取预编译的数据库操作对象
// sql语句的框架,其中一个? 便是一个占位符,一个?接收一个值
String sql = "select * from user where username = ? and userPwd = ? ;";
ps = conn.prepareStatement(sql);
//4. 给占位符传值,第一个?问号下标是1
ps.setString(1, loginName);
ps.setString(2, loginPwd);
rs = ps.executeQuery(sql);
//5. 处理查询结果集(只有第四步执行是select语句,才需要处理)
if (rs.next()){
//登陆成功
loginSuccess = true;
}else {
loginSuccess = false;
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
finally {
//6. 释放资源
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
return loginSuccess;
}
/**
* 初始化界面
* @return
*/
private static Map<String, String> initUI() {
Scanner s = new Scanner(System.in);
System.out.println("欢迎登陆");
System.out.print("用户名:");
String loginName = s.nextLine();
System.out.print("用户密码:");
String loginPwd = s.nextLine();
Map<String,String> userloginInfo = new HashMap<>();
userloginInfo.put("loginName", loginName);
userloginInfo.put("loginPwd", loginPwd);
return userloginInfo;
}
}
使用statement的场景
- 查询要进行数据升降排序
- 需要传关键字进去编译
JDBC事务
- 默认是执行一次DML语句,则自动提交一次
package Sql;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Scanner;
public class Test {
public static void main (String[] args){
//JDBC代码
ResourceBundle bundle = ResourceBundle.getBundle("user");
String driver = bundle.getString("driver");
String url = bundle .getString("url") ;
String user = bundle .getString("user") ;
String password = bundle .getString ("password") ;
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
//1. 注册驱动
Class.forName(driver);
//2. 获取连接属于(属于进程间的通信,使用后一定要关闭)
conn = DriverManager.getConnection(url, user, password);
// 将自动提交设为自动提交,开启事务
conn.setAutoCommit(false);
//3. 获取预编译的数据库操作对象
// sql语句的框架,其中一个? 便是一个占位符,一个?接收一个值
String sql = "update t_act set balance = ?where act_no =?;";
ps = conn.prepareStatement(sql);
//4. 给占位符传值,第一个?问号下标是1
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? "转账成功":"转账失败");
//5. 提交事务
conn.commit();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
if (conn != null){//事务回滚
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
finally {
//6. 释放资源
if (rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
锁
-
行级锁(悲观锁)
当select语句后加for update;后,查询的数据记录,在当前的事务还没结束前,别的事务无法对上述的数据修改 -
乐观锁,支持并发,事务不需要排队。还需要一个版本号