目录
1、prepareStatement的使用
select * from t_user where userName=xxx and password=xxx
这个SQl语就是通过我们的用户名 和密码 查询用户对象
这个SQL语句经常用来 进行用户的登陆操作
前端传递过来 用户名 ----- 密码
接下来我们就可以通过用户名和密码去查询用户对象
public class Test001 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
//这里模拟的是前端页面传递过来的这个值
private static String userName="jonwen";
private static String password="123";
public static void main(String[] args){
Connection connection=null;
Statement statement=null;
//首先是 加载驱动
try {
// Class.forName("com.mysql.jdbc.Driver");
//通过DriverManager对象 获取咋们的连接
//connection这个就相当于是操作修的路
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//通过Connection获取咋们的操作数据库的对象
//下面这个对象 就是专门用来操作数据库的
statement = connection.createStatement();
//这种方式有 潜在的问题存在的
// 我们是将整个SQL语句带数据 发送到了 数据库管理系统
//现在假设我们在进行执行SQL的过程中 别人拦截了我们的信息 还能拿到数据库的连接信息 数据库名字 数据库的编码...
// select * from t_user where userName='xiaobobo' and password='123'
//他在上面的SQL语句上 跟你 拼接上 这样一句 or 1=1
// select * from t_user where userName='xiaobobo' and password='123' or 1=1 这个就是比较经典的SQL的注入问题
//那么于是在这种场景下 另外一种 Statement名字叫做 PrepareStatement就产生了
//在开发中使用的比较多的 应该是 Preparestatement使用的比较多的
ResultSet resultSet = statement.executeQuery("select * from t_user where userName='" + userName + "' and password='" + password + "'");
//接下来我们就可以遍历这个值了
while (resultSet.next()){
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
String id = resultSet.getString("id");
System.out.println("用户名:"+userName+"----password:"+password+"---id--"+id);
}
} catch (Exception e) {
System.out.println("驱动没找到....");
} finally {
//关闭资源
try {
statement.close();
connection.close();
} catch (SQLException e) {
System.out.println("关闭资源遇到异常....");
}
}
}
}
PrepareStetement他叫做预编译的SQL的一个执行器
啥意思呀?
意思是他可以将SQL的骨架 和 SQL中的值 进行分离传输
先传输 SQL语句的骨架到 数据库管理系统上去 进行预编译
select * from t_user where userName=? and password=?
第二步:再发送我们SQL语句中需要的值 传递到 上面的SQL语句中去 这个就是咋们的PrepareStetement
public class Test002 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
//这里模拟的是前端页面传递过来的这个值
private static String userName="jonwen";
private static String password="123";
public static void main(String[] args){
Connection connection=null;
PreparedStatement statement=null;
//首先是 加载驱动
try {
// Class.forName("com.mysql.jdbc.Driver");
//通过DriverManager对象 获取咋们的连接
//connection这个就相当于是操作修的路
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//这句话就会将SQL发送到数据库管理系统去进行编译
// 这里的? 表示的是一个占位符 表示的是 需要一个值
statement = connection.prepareStatement("select * from t_user where userName=? and password=?");
//接下来再给这个SQL语句设置值
statement.setString(1,userName);
statement.setString(2,password);
//下面就 可以来进行查询了
ResultSet resultSet = statement.executeQuery();
//接下来我们就可以遍历这个值了
while (resultSet.next()){
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
String id = resultSet.getString("id");
System.out.println("用户名:"+userName+"----password:"+password+"---id--"+id);
}
} catch (Exception e) {
System.out.println("驱动没找到....");
} finally {
//关闭资源
try {
statement.close();
connection.close();
} catch (SQLException e) {
System.out.println("关闭资源遇到异常....");
}
}
}
}
2、批处理的使用
我们有没有这种场景
1、我们一次性需要向数据库 插入100条数据
2、我们有没有可能一次性执行多种不同类型的SQL语句呢?
3、一次性执行1000条或者 1000条数据 直接运行到数据库中去
为了解决这个问题呢?批处理在SQL中就被使用进去了
2.1、场景(执行不同的SQL语句)
package com.qf.edu.batch;
import java.sql.*;
public class Test003 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
//这里模拟的是前端页面传递过来的这个值
private static String userName="jonwen";
private static String password="123";
public static void main(String[] args){
Connection connection=null;
Statement statement=null;
//首先是 加载驱动
try {
// Class.forName("com.mysql.jdbc.Driver");
//通过DriverManager对象 获取咋们的连接
//connection这个就相当于是操作修的路
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//准备两个SQL语句
//这种场景很少见 我是没有遇到过
String sql1="update t_user set userName='xxx' where id>1000";
String sql2="insert into t_user(userName) values('美女好')";
statement = connection.createStatement();
statement.addBatch(sql1);
statement.addBatch(sql2);
//在这里就可以统一的执行这个SQL语句了
//统一执行上面的SQL语句和值
statement.executeBatch();
} catch (Exception e) {
System.out.println("驱动没找到....");
} finally {
//关闭资源
try {
statement.close();
connection.close();
} catch (SQLException e) {
System.out.println("关闭资源遇到异常....");
}
}
}
}
2.2、场景(执行100条SQL语句)
package com.qf.edu.batch;
import java.sql.*;
public class Test001 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
//这里模拟的是前端页面传递过来的这个值
private static String userName="jonwen";
private static String password="123";
public static void main(String[] args){
Connection connection=null;
PreparedStatement statement=null;
//首先是 加载驱动
try {
// Class.forName("com.mysql.jdbc.Driver");
//通过DriverManager对象 获取咋们的连接
//connection这个就相当于是操作修的路
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//这句话就会将SQL发送到数据库管理系统去进行编译
// 这里的? 表示的是一个占位符 表示的是 需要一个值
statement = connection.prepareStatement("insert into t_user(userName,password) values(?,?)");
//接下来咋们就可以来设置这个值了
for (int i = 0; i < 100; i++) {
statement.setString(1,"xiaobobo"+i);
statement.setString(2,"123"+i);
//这个相当于没有直接执行 把这个结果放到了队列中 后面统一执行
statement.addBatch();
}
//在这里就可以统一的执行这个SQL语句了
//统一执行上面的SQL语句和值
statement.executeBatch();
} catch (Exception e) {
System.out.println("驱动没找到....");
} finally {
//关闭资源
try {
statement.close();
connection.close();
} catch (SQLException e) {
System.out.println("关闭资源遇到异常....");
}
}
}
}
3、事务的处理
什么是事务:
这个事务 可以看成是我们在业务开发的时候 要执行的业务(简单的说就是你在开发中要做的事这个就称为事务)。你可以认为就叫做事务、也可以认为时候我们在进行业务操作的时候 执行的一个一个小的执行单元 这个就称为事务。
事务具有 如下的 几大特性原子性:所做的操作 要么 同时成功要么同时失败 这个就叫做原子性 这个也是事务中最重要的特性
一致性:你可以这么认为 一次事务的操作 实际上 就是数据库中 从一个状态到另一个状态。数据库库中只是包含了 事务成功后的状态 事务失败的状态是没有保存的 这个就称为一致性
隔离性:指的是 事务之间的操作 是不会相互影响的 你操作你的 我操作我的 我们之间相互是不会影响的 这个就业类似于咋们前面将的 线程池的中线程 在执行任务时候的 隔离 是一样的
持久性:事务一旦执行成功 那么 对于数据库的操作 是永久的 、除非下一次的事务又来进行一次的更改 这样就变成了下一次的状态 这个就是咋们的持久性
3.1、就是事务的使用
1、设置手动提交 ---- 因为这个里面已经包含了 打开事务
2、提交事务
3、执行回滚
事例1
package com.qf.edu.tranaction;
import javax.swing.plaf.nimbus.State;
import java.sql.*;
public class Test002 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
public static void main(String[] args) throws SQLException {
Connection connection=null;
Statement statement=null;
//首先是 加载驱动
try {
//获取连接
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//设置手动提交 默认是自动提交
connection.setAutoCommit(false);
//第一个要执行的操作
statement = connection.createStatement();
statement.executeUpdate("update t_user set userName='hhhh' where id=4");
int k=1/0;
//在这里我们就可以模拟异常了
statement.executeUpdate("update t_user set userName='wwww' where id=5");
//进行手动的提交
connection.commit();
} catch (Exception e) {
System.out.println("这里会执行回滚....");
connection.rollback();
} finally {
//关闭资源
try {
statement.close();
connection.close();
} catch (SQLException e) {
System.out.println("关闭资源遇到异常....");
}
}
}
}
事例2
package com.qf.edu.tranaction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test003 {
//如果你访问的是 本地 那么localhost:3306可以省略
// jdbc:协议 mysql:子协议 ip地址 端口 数据库的名字
private static final String URL="jdbc:mysql:///cd2106";
//如果你访问的是远程数据库 host:3306 这个就不能省略
private static final String URL_NEW="jdbc:mysql://localhost:3306/cd2106?useUnicode=true&characterEncoding=UTF-8";
private static final String USER="root";
private static final String PASSWORD="root";
public static void main(String[] args) throws SQLException {
Connection connection=null;
//首先是 加载驱动
try {
//获取连接
connection = DriverManager.getConnection(URL_NEW, USER, PASSWORD);
//设置手动提交 默认是自动提交
connection.setAutoCommit(false);
//第一个要执行的操作
PreparedStatement preparedStatement = connection.prepareStatement("update t_user set userName='hhhh' where id=7");
preparedStatement.executeUpdate();
int k=1/0;
//在这里我们就可以老模拟异常了
PreparedStatement preparedStatement1 = connection.prepareStatement("update t_user set userName='uuuu' where id=8");
preparedStatement1.executeUpdate();
//进行手动的提交
connection.commit();
} catch (Exception e) {
System.out.println("这里会执行回滚....");
connection.rollback();
} finally {
}
}
}
4、连接池的使用
大家有没有想过一个问题:
就是我们前面的连接 使用了之后 是不是都要关闭 关闭了 就意味着 这个连接不能再次被使用了 那么我们有没有谱一种策略 这种策略就是我们使用完了这个连接之后 放到一个容器中 这个连接并不被销毁 如果是下次我们还需要来访问这个数据库的话 就直接从容器中 去找 这个连接呢 这样就 避免了 连接的创建 消耗咋们的资源 这个就是咋们的连接池产生的 背景
这个就跟咋们的的 线程池 是一样的 每一次都创建线程的话会 消耗相当一部分的资源 因为线程的创建也需要咋们的CPU的参数 以及资源的分发
4.1、常见的优秀的连接池有哪些呢?
1、DBCP-----今天的市场上用的比较少
2、C3P0------几乎今天也没用了
3、Druid----阿里巴巴开发的------这个在中国今天为止 几乎所有的项目都使用了这个Druid去做连接池
4、Tomcat自带的连接池----用的比较少
4.2、Druid的使用
DataSource这个是所有的连接池的爹
DataSource这个是Sun公司提供的一个数据库的连接池的一个规范
像我们所说的 其他的连接池 实际上只有 这个规范中的一个实现而已
4.2.1、导包
<!--这个是Druid的包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
4.2.2、编写工具类
/**
*德鲁伊的工具类
*/
public class DruidUtils {
private static DruidDataSource dataSource;
private static ThreadLocal<Connection> threadLocal;
static {
//这里就需要加载这个资源文件了
InputStream in = DruidUtils.class.getClassLoader().getResourceAsStream("db.properties");
try {
Properties properties = new Properties();
properties.load(in);
dataSource = new DruidDataSource();
//初始化数据库的连接细信息
//获取所需要的值
dataSource.setDriverClassName(properties.getProperty("driverClassName"));
dataSource.setUrl(properties.getProperty("jdbcUrl"));
dataSource.setUsername(properties.getProperty("username"));
dataSource.setPassword(properties.getProperty("password"));
//这里面其实还有很多的设置
// 这里一般写项目的时候 去找个模板就可以了
dataSource.setMaxActive(100);
dataSource.setMaxWait(1000*60*5);
} catch (IOException e) {
System.out.println("加载Properties文件出现异常了:"+e.getMessage());
}
//下面初始化 ThreadLocal这个类
threadLocal = new ThreadLocal<>();
}
/**
* 这个方法用户获取数据库的连接
*
* @return
*/
public static Connection getConnection() throws SQLException {
Connection connection1 = threadLocal.get();
if (null != connection1) {
return connection1;
}
//如果执行到这里 说明ThreadLocal中是没有这个对象的
connection1 = dataSource.getConnection();
//将上面的连接放到咋们的ThreadLocal中去
threadLocal.set(connection1);
return connection1;
}
/**
* 关闭咋们资源
*/
public static void close() throws SQLException {
Connection connection = threadLocal.get();
if (null != connection) {
connection.close();
}
}
}
4.2.3、编写db.properties文件和资源目录
driverClassName=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql:///cd2106
username=root
password=root
4.2.4、编写测试
/**
* 测试Druid的使用
*/
@Test
public void testDruid(){
try {
Connection connection = DruidUtils.getConnection();
//我们就可以使用这个Connection对象来进行处理了
PreparedStatement preparedStatement = connection.prepareStatement("select * from t_user limit 0,10");
ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()){
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
System.out.println("查询数来的userName是:"+userName+"----password:"+password);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
5、讲一个组件的使用(dbutils)
dbutils这是一个组件 这个组件的主要功能是完成咋们的数据库的访问
你们肯定有个疑问:
就是我们有了JDBC为啥还要使用dbutils呢?
我们的dbutils实际上是 咋们的JDBC的一个封装 因为JDBC本身的使用 代码还是比较复杂的 所以使用了dbutils之后就可以很简单的就完成数据库的访问
dbutils就是咋们的JDBC的一个封装而已 没什么高深的