JDBC连接 防止注入 事件 回滚

1.

JDBC 是一套接口(规范) 那各个厂商想要让java语言去操作他们的数据库,必须实现这套接口
厂商写的一套实现类 我们叫做 数据库驱动
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;


public class JDBCtest {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
	//1.导入数据数据库包 jar包
	//2 加载驱动jar包
		Class.forName("com.mysql.jdbc.Driver");
	//3 获取一个数据库连接对象         参数1:数据库的路径 参数2,3 数据库的用户名和密码
		String  url = "jdbc:mysql:///mydb_01";
		String user = "root";
		String password = "root";
		Connection conn = DriverManager.getConnection(url, user, password);
	//4 通过连接对象获取操作对象	
		Statement statement = conn.createStatement();//用于执行静态 SQL 语句并返回它所生成结果的对象。
 							     // statement是一个接口  
	//5定义sql语句
		String sql = "insert into tescher values(3,'rrr','333')";
	//6执行语句
		int i = statement.executeUpdate(sql);//返回此语句改变的行数
		if(i!=0){
			System.out.println("成功");
		}else{
			System.out.println("失败");
		}
	//7释放资源
		conn.close();
		statement.close();
	}
}


2.
获取Connection对象:
Connection conn = DriverManager.getConnection(url,user,password);
url:访问数据库的路径
jdbc:     mysql://    192.168.3.100:     3306     /day
              主协议    子协议 ip地址       端口号  数据库名称

* 细节:如果连接的是本地的数据库, 则ip和端口可以省略
jdbc:mysql:///day04
3.
Connection:数据库连接对象
* 创建执行sql的对象
* createStatement:创建Statement对象
* prepareStatement:创建preparedStatement对象
* 可以防止sql注入,提高执行效率
* prepareCall: 创建preparedCall对象
* 执行存储过程的
4.
Statement:执行sql的对象

* executeUpdate(sql):执行DML语句  (增、删、改)
* 返回值:int,代表影响的行数
* executeQuery(sql):执行DQL语句 (查询)
* 返回值:ResultSet对象  结果集对象,对结果集的封装

* execute(sql):执行任意语句
       * 返回值:boolean,执行成功与否
5.
 PreparedStatement:执行sql的对象
* 登陆:
如果使用statement,可能发生sql注入。

* 功能:
* 预防sql注入

* 使用方式:
1.定义sql时,所有的参数位置 需要 使用 ? 作为占位符
2.Connection对象获取执行sql 对象 prepareStatement(sql)
3.给占位符 ? 赋值
* setXxx(参数1,参数2):
* 参数1:?出现的位置 从1开始
* 参数2:?对应的值
4.执行sql时,使用不带参数的方法
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;




6.预编译  查询表  抽取工具类

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;


public class JDBC03 {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		//拷贝JAR包
		//加载驱动
		//Class.forName("com.mysql.jdbc.Driver");
		//获取连接对象
		//Connection conn = DriverManager.getConnection("jdbc:mysql:///mydb_01", "root", "root");
		//通过连接对象获取预编译操作对象
		Connection conn = JDBCutils.getConnection();
		String sql  = "select * from tescher where id = ?";
		PreparedStatement statement = conn.prepareStatement(sql);
		statement.setInt(1, 3);// 给问号赋值   第一个参数:id位于表中的第几个参数 第二个参数:?的值    Int表示?的类型
		//执行sql语句
		ResultSet resultSet = statement.executeQuery();
		while(resultSet.next()){//如果查到了 光标将发生跳转  返回值变为true
			int id = resultSet.getInt(1);
			String name = resultSet.getString(2);
			String sex = resultSet.getString(3);
			System.out.println(id+name+sex);
		}
//		conn.close();
//		statement.close();
//		resultSet.close();
		JDBCutils.close(conn, statement, resultSet);
	}
}

工具类
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;




public class JDBCutils {
	//全局变量
	 public static String url;
	 public static String user;
	 public static String password;
	 
	 //静态代码块
	static{
		 url  = "jdbc:mysql:///mydb_01";
		 user = "root";
		 password = "root";
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//不让外界创建对象  私有构造(外界只能通过类名.方法名  来使用)
	private JDBCutils(){
		super();
	}
	
	//返回连接对象
	public static Connection getConnection() throws SQLException{
		return DriverManager.getConnection(url, user, password);
	}
	
	//关闭资源
	public static void close(Connection conn ,Statement statement , ResultSet result ) throws SQLException{
		if(conn != null){
			conn.close();
		}
		if(statement!= null){
			statement.close();
		}
		if(result!= null){
			result.close();
		}
	}
	
	//要是有的没有用到结果集(ResultSet) 这时候就需要方法重载
	public static void close(Connection conn, Statement statement) throws SQLException{
		if(conn!=null){
			conn.close();
		}
		if(statement!=null){
			statement.close();
		}
	}
	
}




7. 
读取表中的数据

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;


public class JDBC02 {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		//导入驱动JAr包
		//加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//获取链接对象
		Connection conn = DriverManager.getConnection("jdbc:mysql:///mydb_01", "root", "root");
		//通过连接对象获取操作对象
		Statement statement = conn.createStatement();
		//定义sql语句
		String sql = "select * from tescher";
		//executeUpdate(sql):执行DML语句  (增、删、改)  返回值:int,代表影响的行数
                //executeQuery(sql):执行DQL语句 (查询)  返回值:ResultSet对象  结果集对象,对结果集的封装	
                //execute(sql):执行任意语句        返回值:boolean,执行成功与否
		//执行sql语句
		ResultSet resultSet = statement.executeQuery(sql);
		//创建集合来存储读取到的数据 然后输出遍历
		ArrayList<User> list = new ArrayList<User>();
		//boolean b = resultSet.next();//返回值是用来判断是否还有下一行
		while(resultSet.next()){//在结果集里面 按照顺序下移一行
			int id = resultSet.getInt(1);
			String name = resultSet.getString(2);
			String sex = resultSet.getString(3);
			User user = new User(id,name,sex);//从数据库里面取出数据 是想使用这些数据 先封装到对象 再把每个对象 装到集合里
			list.add(user);
		}
		//遍历集合
		System.out.println(list);
		//释放资源
		conn.close();
		statement.close();
		resultSet.close();
	
	}
}


8.防止sql注入   采取预编译  

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;


public class JDBC04 {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入姓名");
		String username = sc.next();
		System.out.println("请输入密码");
		String password = sc.next();
		
		Class.forName("com.mysql.jdbc.Driver");
		Connection conn = DriverManager.getConnection("jdbc:mysql:///mydb_01", "root", "root");
		
		//定义sql语句 通配符?代替数据
		String sql = "select * from 登陆表格 where username = ? and password = ? ";
		
		//获取预编译操作对象
		PreparedStatement statement = conn.prepareStatement(sql);
		
		//给通配符赋值   参数1为?在表中的位置  参数2为?的值
		statement.setString(1, username);
		statement.setString(2, password);
		
		//执行sql语句
		ResultSet resultSet = statement.executeQuery();
		if(resultSet.next()){
			System.out.println("登陆成功");
		}
		else{
			System.out.println("登陆失败");
		}
		//释放资源
		resultSet.close();
		statement.close();
		conn.close();	
	}
}


9.事件(以银行转账为例)

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


import JDBC03.JDBCutils;
//zs给ls转账100
public class jdbc05 {
	public static void main(String[] args) throws Exception {
		//获取连接对象
		Connection conn = JDBCutils.getConnection();
		
		//定义sql语句
		String sql1 = "update bank set money=money-100 where username = ?";//转出
		String sql2 = "update bank set money=money+100 where username = ?";//转入
		
		//获取预编译对象
		PreparedStatement statement1 = conn.prepareStatement(sql1);
		PreparedStatement statement2 = conn.prepareStatement(sql2);
		
		//给?赋值  参数1为username在表中的位置  参数2为?的值
		statement1.setString(1, "zs");
		statement2.setString(1, "ls");
		
		//执行sql语句
		statement1.execute();
		statement2.execute();
		
		//释放资源
		JDBCutils.close(conn, statement1);
		JDBCutils.close(conn, statement2);	
	}
}

现在制造一个异常来模拟:当张三将钱转出去,服务器发生异常,强制终止

             
   //执行sql语句
		statement1.execute();
		
		//人为加一个异常
		System.out.println(1/0);
		
		statement2.execute();


这时候会发现zs转账过去了 但ls并没有收到 这时引入 事件


基本概念:
      事务使指一组最小逻辑操作单元,里面有多个操作组成。 组成事务的每一部分必须要同时提交成功,如果有一个操作失败,整个操作就回滚。


事务ACID特性
原子性(Atomicity)
          原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。 
一致性(Consistency)
          事务必须使数据库从一个一致性状态变换到另外一个一致性状态。
隔离性(Isolation)
          事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)
          持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响


事务的特性:
  原子性,是一个最小逻辑操作单元 !
  一致性,事务过程中,数据处于一致状态。                                                      
  持久性, 事务一旦提交成功,对数据的更改会反映到数据库中。
  隔离性, 事务与事务之间是隔离的。




针对上述服务器异常问题  就需要 回滚来解决
        Connection SetAutoCommit(boolean b):开启事物,默认为true,b=false则开启事物
        Connection rollback():回滚事物到初始状态(当程序运行异常,张三李四账户余额不变 所以是在异常处抓一下)
        Connection commit():提交事物

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


import JDBC03.JDBCutils;
//zs给ls转账100
public class jdbc05 {
	public static void main(String[] args) throws Exception {
		//建立连接
		Connection conn = JDBCutils.getConnection();
		
		//开启事务
		conn.setAutoCommit(false);
		
		//定义sql语句
		String sql1 = "update bank set money=money-100 where username = ?";//转出
		String sql2 = "update bank set money=money+100 where username = ?";//转入
		
		//获取预编译对象
		PreparedStatement statement1 = conn.prepareStatement(sql1);
		PreparedStatement statement2 = conn.prepareStatement(sql2);
		
		//给?赋值  参数1为username在表中的位置  参数2为?的值
		statement1.setString(1, "zs");
		statement2.setString(1, "ls");
		
		try {
			//执行sql语句
			statement1.execute();
			
			//人为加一个异常
			System.out.println(1/0);
			
			statement2.execute();
		} catch (Exception e) {
			//一旦发生异常 回滚到最初状态
			conn.rollback();
			
		}finally{
			//提交事务
			conn.commit();
		}
		
		//释放资源
		JDBCutils.close(conn, statement1);
		JDBCutils.close(conn, statement2);	
	}
}


当服务器发生异常 数据会回滚到最原始


10.事物回滚点


事物回滚点 当程序中执行两次转账,第一次成功,第二次失败,回滚到初始状态 但我想第一转账成功保留,只回滚到第二次转账前的状态,怎么办?
 需要设置一个回滚点 Connection setSavepoint():
 在两次之间设置一个回滚点 Connection rollback(Connection setSavepoint()):回滚到回滚点上(即回滚到第一次转账结束后)


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Savepoint;


import JDBC03.JDBCutils;
//zs给ls转账100
public class jdbc05 {
	public static void main(String[] args) throws Exception {
		Savepoint savepoint = null;
		//建立连接
		Connection conn = JDBCutils.getConnection();
		
		//开启事务
		conn.setAutoCommit(false);
		
		//定义sql语句
		String sql1 = "update bank set money=money-100 where username = ?";//转出
		String sql2 = "update bank set money=money+100 where username = ?";//转入
		
		//获取预编译对象
		PreparedStatement statement1 = conn.prepareStatement(sql1);
		PreparedStatement statement2 = conn.prepareStatement(sql2);
		
		//给?赋值  参数1为username在表中的位置  参数2为?的值
		statement1.setString(1, "zs");
		statement2.setString(1, "ls");
		
		try {
			//执行sql语句
			//第一次转账(正常)
			statement1.execute();
			statement2.execute();
			
			//在第一次和第二次转账之间设置回滚点
			 savepoint = conn.setSavepoint();
			//第二次转账(异常)
			statement1.execute();
			
			//人为加一个异常
			System.out.println(1/0);
			
			statement2.execute();
		} catch (Exception e) {
			//一旦发生异常 回滚到设置的回滚点
			conn.rollback(savepoint);
			
		}finally{
			//提交事务
			conn.commit();
		}
		
		//释放资源
		JDBCutils.close(conn, statement1);
		JDBCutils.close(conn, statement2);	

	}
}

















  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值