一、PreparedStatement和Statement的区别
1、PreparedStatement使用?占位符代替参数
String sql = "update users set name = ? where id = ?";
预编译sql,然后设置结果
public static void main(String[] args) {
login("' or ' 1=1","123456");
}
public static void login(String username,String password){
Connection conn = null;
PreparedStatement stat = null;
ResultSet rs = null;
try {
conn = utils.getConn();
String sql = "select * from users where `name`=? and psw=?";
stat = conn.prepareStatement(sql);
stat.setString(1,username);
stat.setString(2,password);
rs = stat.executeQuery();
if (rs.next()) {
System.out.println("rs:" + rs.getObject("id")+" "+rs.getObject("name")+" "+rs.getObject("psw"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
utils.relax(conn,stat,null);
}
}
}
//此时就不会再出现sql注入问题,PreparedStatement把传递进来的参数当作字符,假设传递的参数中有转译字符就直接忽略
//''会被直接转义
PreparedStatement.set(1,"licunzhi");//意思就是第一个?设置值为“liucnzhi”
PreparedStatement.set(2,"why");//第二个?设置值为why....以此类推
二、使用JDBC执行事务
package com.baidu.JDBC; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class TestUpdate { public static void main(String[] args) { Connection conn = null; PreparedStatement stat = null; ResultSet rs = null; try { conn = utils.getConn(); //关闭自动提交 这里直接开启一个事务 不需要像数据库一样操作 conn.setAutoCommit(false); String sql1 = "update account set money=money-100 where id=1"; stat = conn.prepareStatement(sql1); stat.executeUpdate(); String sql2 = "update account set money=money+100 where id=2"; stat = conn.prepareStatement(sql2); stat.executeUpdate(); //业务完毕 提交事务 conn.commit(); System.out.println("转账成功"); } catch (SQLException e) { try { //失败则回滚数据,不写也会自动回滚 conn.rollback(); } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally{ utils.relax(conn,stat,null); } } }
代码实现:
1、开启事务
2、一组业务执行完毕,提交事务
3、可以再catch语句中i希纳是的定义回滚数据,但默认失败就会回滚
三、数据库连接池
常见的数据库连接池:
DBCP C3P0 【Druid(德鲁伊) 阿里巴巴】
池化技术:准备一些预先的资源,直接连接预先准备好的资源
连接池可以自己手写,实现接口DataSource
使用数据库连接池之后我们就不需要编写连接数据库的代码了
1、dbcp
首先将两个jar包导入程序中,add librarys
接下来配置文件百度一个
#连接设置 driverClassName=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC username=root password=space999 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=gbk #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
接下来工具类,省去了读取配置文件每个字段的步骤
package space.bilibili.com; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class Jdbc_Utils { private static Connection conn = null; private static DataSource dataSource = null; static{ try{ //将配置文件放入流中 InputStream in = Jdbc_Utils.class.getClassLoader().getResourceAsStream("dbcpconfig.properties"); //加载读取配置文件的类 Properties properties = new Properties(); //加载流中的配置文件 properties.load(in); dataSource = BasicDataSourceFactory.createDataSource(properties); conn = dataSource.getConnection(); } catch (Exception e) { e.printStackTrace(); } } //获取连接 public static Connection getConn() throws SQLException { return dataSource.getConnection(); } //释放资源 public static void release(Connection conn,Statement stat,ResultSet rs){ if(rs!=null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stat!=null) { try { stat.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } }
接下来就是测试插入代码:
package space.bilibili.com; import space.urbeautiful.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; public class TestInsert { public static void main(String[] args) { Connection conn = null; PreparedStatement stat = null; ResultSet rs = null; try { conn = Jdbc_Utils.getConn(); String sql = "insert into account(id,`name`,money) values(5,'why',20000)"; stat = conn.prepareStatement(sql); int i = stat.executeUpdate(); if(i>0){ System.out.println("插入成功"); } } catch (Exception e) { e.printStackTrace(); }finally{ JdbcUtils.release(conn,stat,rs); } } }
2、C3P0