一:JDBC
1.JDBC 概述
-
JDBC(Java Data Base Connectivity) 是 Java 访问数据库的标准规范.是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。是Java访问数据库的标准规范.
-
JDBC 原理: JDBC是接口,驱动是接口的实现,没有驱动将无法完成数据库连接,从而不能操作数据库!每个数据库厂商都需要提供自己的驱动,用来连接自己公司的数据库,也就是说驱动一般都由数据库生成厂商提供。
-
JDBC就是由sun公司定义的一套操作所有关系型数据库的规则(接口),而数据库厂商需要实现这套接口,提供数据库
驱动jar包, 我们可以使用这套接口编程,真正执行的代码是对应驱动包中的实现类。
2.JDBC 开发
- 1.加载驱动:Class.forName(数据库驱动实现类)
- 2.获取连接:使用 DriverManager类的静态方法getConnection方法,获取数据库的连接
- 3.获取Statement对象
- 4.处理结果集:只有在进行查询操作的时候, 才会处理结果集ResultSet
- 5.释放资源:先开的后关,后开的先关,ResultSet ==> Statement ==> Connection
3.SQL注入问题
- SQL注入: 我们让用户输入的密码和 SQL 语句进行字符串拼接。用户输入的内容作为了 SQL 语句语法的一部分,改变了原有SQL 真正的意义,以上问题称为 SQL注入。
# SQL注入演示 -- 填写一个错误的密码 SELECT * FROM jdbc_user WHERE username = 'tom' AND PASSWORD = '123' OR '1' = '1'; 相当于 select * from user where true=true; 查询了所有记录 如果这是一个登陆操作,那么用户就登陆成功了.显然这不是我们想要看到的结果
- 要解决 SQL 注入,就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。
4.预处理对象
-
PreparedStatement 是Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的SQL语句对象.
-
预编译: 是指SQL语句被预编译,并存储在PreparedStatement对象中。然后可以使用此对象多次高效地执行该语句。
-
PreparedStatement特点: 因为有预先编译的功能,提高SQL的执行效率。可以有效的防止 SQL 注入的问题,安全性更高
-
Statement 与 PreparedStatement的区别
- 1.Statement用于执行静态SQL语句,在执行时,必须指定一个事先准备好的SQL语句。
- 2.PrepareStatement是预编译的SQL语句对象,语句中可以包含动态参数“?”,在执行时可以为“?”动态设置参数值。
- 3.PrepareStatement可以减少编译次数提高数据库性能。
5.JDBC 控制事务
- 使用Connection中的方法实现事务管理
- void setAutoCommit(boolean autoCommit):参数是 true 或 false 如果设置为 false,表示关闭自动提交,相当于开启事务
- void commit():提交事务
- void rollback():回滚事务
- 开发步骤
- 1.获取连接
- 2.开启事务
- 3.获取到 PreparedStatement , 执行两次更新操作
- 4.正常情况下提交事务
- 5.出现异常回滚事务
- 6.最后关闭资源
public class TestJDBCTransaction {
//使用JDBC操作事务
public static void main(String[] args) {
Connection con = null;
PreparedStatement ps = null;
try {
//1.获取连接
con = JDBCUtils.getConnection();
//2.开启事务
con.setAutoCommit(false); //手动提交事务
//3.获取预处理对象 执行SQL (两次修改操作)
//3.1 tom账户 - 500
ps = con.prepareStatement("update account set money = money - ? where name = ?");
ps.setDouble(1,500.0);
ps.setString(2,"tom");
ps.executeUpdate();
//模拟 tom转账之后出现异常
System.out.println(1 / 0);
//3.2 jack账户 + 500
ps = con.prepareStatement("update account set money = money + ? where name = ?");
ps.setDouble(1,500.0);
ps.setString(2,"jack");
ps.executeUpdate();
//4.提交事务 (正常情况)
con.commit();
System.out.println("转账成功! !");
} catch (SQLException e) {
e.printStackTrace();
//5.出现异常就回滚事务
try {
con.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
//6.释放资源
JDBCUtils.close(con,ps);
}
}
}
二:数据库连接池和DBUtils
-
连接池: 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交给了连接池.
-
连接池的好处: 用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
-
普通 JDBC方式:
-
连接池方式:
-
Java为数据库连接池提供了公共的接口: javax.sql.DataSource,各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!常见的连接池有 DBCP连接池, C3P0连接池, Druid连接池,
-
DBCP 是一个开源的连接池,是Apache成员之一,在企业开发中也比较常见,tomcat内置的连接池。
- 常见配置项:
- driverClassName: 数据库驱动名称
- url: 数据库地址
- username: 用户名
- password: 密码
- maxActive: 最大连接数量
- maxIdle: 最大空闲连接
- minIdle: 最小空闲连接
- initialSize: 初始化连接
/**
* DBCPUtils 工具类
*/
public class DBCPUtils {
//1.定义常量 保存数据库连接的相关信息
public static final String DRIVERNAME = "com.mysql.jdbc.Driver";
public static final String URL = "jdbc:mysql://localhost:3306/lagou_jy?characterEncoding=UTF-8";
public static final String USERNAME = "root";
public static final String PASSWORD = "root";
//2.创建连接池对象 (有DBCP提供的实现类)
public static BasicDataSource dataSource = new BasicDataSource();
//3.使用静态代码块进行配置
static{
dataSource.setDriverClassName(DRIVERNAME);
dataSource.setUrl(URL);
dataSource.setUsername(USERNAME);
dataSource.setPassword(PASSWORD);
dataSource.setMaxActive(20);
}
//4.获取连接的方法
public static Connection getConnection() throws SQLException {
//从连接池中获取连接
Connection connection = dataSource.getConnection();
return connection;
}
//5.释放资源方法
public static void close(Connection con, Statement statement){
if(con != null && statement != null){
try {
statement.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
//5.释放资源方法
public static void close(Connection con, Statement statement, ResultSet resultSet){
if(con != null && statement != null && resultSet != null){
try {
resultSet.close();
statement.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
-
C3P0 是一个开源的JDBC连接池,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等。
配置文件c3p0-config.xml,文件名不可更改,直接放到src下,也可以放到到资源文件夹中 <c3p0-config> <!--默认配置--> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/lagou_jy?characterEncoding=UTF-8</property> <property name="user">root</property> <property name="password">root</property> <!-- initialPoolSize:初始化时获取三个连接, 取值应在minPoolSize与maxPoolSize之间。 --> <property name="initialPoolSize">3</property> <!-- maxIdleTime:最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。--> <property name="maxIdleTime">60</property> &