什么是JDBC?
JDBC(Java Data Base Connectivity,Java数据库连接)
java数据库连接,java可以操作各种关系型数据库
本质上就是一个普通的java类,数据库厂商提供的驱动jar包,来实现sun公司提供一套"应用程序接口规范",建立与数据库的连接,向数据库发起查询需求,以及处理数据库返回结果
java.sql.Driver 驱动接口
java.sql.DriverManager:驱动管理类(管理jdbc的驱动服务)
java.sql.Connection:与特定数据库的一种会话连接
java.sql.Statement:执行静态sql语句(执行对象,操作数据库)
JDBC的基本操作步骤
DML语句
//1)导包并注册驱动
Class.forName("com.mysql.jdbc.Deiver")
//2)获取数据库的连接对象
Connection connection = DriverManager.getConnection(
url="jdbc:mysql://localhost:3306/myee_2203",
"username",
"password"
);
//3)准备sql
String sql = "select * from 表名"
//4)通过连接获取数据库执行对象
Statement statement = connection.createStatement();
//5)执行sql,发送给数据库
int count = statement.executeUpdate(sql);
//6)输出结果
System.ou.println("影响了"+count+"行");
//7)释放资源
statement.close();
connection.close();
DQL语句
//1)导包,注册驱动
Class.forName("com.mysql.jdbc.Driver")
//2)创建数据库连接对象
Connection connection = DriverManager.getconnection(
url="jdbc:mysql://localhost:3306/myee_2203",
"username",
"password"
);
//3)准备sql
String sql = "select * from 表名";
//4)获取执行对象Statement
Statement statement = connection.createStatement();
//5)执行dql语句
ResultSet resultSet = statement.executeQuery();
//6)遍历结果集的数据
while(resultSet.next()){
字段类型 变量名=resultSet.getXxx("字段名称");
//或者是 字段类型 变量名=resultSet.getXXX(列的索引值);
//列的索引值1...开始
}
//7)释放资源
resultSet.close();
statement.close();
connection.close();
封装JDBC基本操作的工具类的步骤
//在src目录下:类路径 xxx.properties
//driverClass=com.mysql.jdbc.Driver
//url=jdbc:mysql://localhost:3306/库名
//username=root
//password=登录的密码
class JdbcUtils{
private static String driverClass = null;
private static String url = null;
private static String username = null;
private static String password = null;
private JdbcUtils(){}
//提供静态代码块:随着类的加载而加载
static{
//创建属性列表:属性集合类 Properties
Properties prop = new Properties();
//读取配置文件 获取配置文件所在的输入流对象
InputStream inputStream = JdbcUtils.class.getClassLoader().getResurcesAsStream("xxx.properties");
//将流对象中的加载属性列表prop
prop.load(inputStream);
//通过key获取它里面的value
driverClass = prop.getProperty("driverClass");
url = prop.getProperty("url");
username = prop.getProperty("username");
password = prop.getProperty("password");
//注册驱动
Class.forName(driverClass);
}
//获取连接对象
public static Connection getConnection(){
Connection conn=DriverManager.getConnection(url,username,password);
return conn;
}
//释放资源--关闭相关系统资源(发送sql到数据库Statement执行对象,Connection,ResultSet)
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
public static void close(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
e.printStackTrice();
}
}
}
}
}
Statement对象和PreparedStatement对象的区别
1)执行效率的区别
Statement对象:执行sql,每一次将sql都需要发送一次,相对于PreparedStatement对象效率低,不用它的原因:数据库的性能优化----->减少服务器的交互次数(和数据库的交互次数减少)
PreparedStatement对象:预编译对象,执行参数化的sql,直接先发送给数据库,数据库会进行校验(参数类型,以及参数的字段是哪一列),并且保存在预编译对象中,可以不断的重新赋值,执行sql效率高
2)是否存在sql注入的区别
Statement对象:执行的sql语句,都是静态化sql,sql存在字符串拼接,就会导致可能出现sql注入,非常不安全
举例:select * from user where username='"+变量名+"'and password'"+值...+"';
PreparedStatement预编译对象:每次是在自己内存中直接赋值对应的值,sql语句永远是占位符号?
select * from user where username= ? and password= ?;
不会造成sql注入问题,非常安全
数据库连接池
java.sql.DataSource:物理数据源的工厂,是sun公司提供的接口---最终替代DriverManager:管理jdbc的驱动服务,里面有一个Connection getConnection();直接获取连接对象
数据库厂商提供对应的连接池jar包:Druid
数据库连接池的好处:可以初始化连接数量,当某个线程使用某个连接对象时候,连接对象就会被这个线程持有,当这个线程结束了释放连接对象会将连接对象归还到数据库连接池中等待下一次利用
通过Druid获取数据源的操作步骤
1)导入包 druid-1.1.10.jar
2)获取数据库连接对象--提前配置好数据库连接池的配置文件druid.properties
配置文件的内容key是DruidDataSource里面的参数信息
配置好数据库的基本信息以及其他连接信息
initialSize:初始化数量
maxActive:最大激活数量
maxWait:最大等待时间(毫秒值)
maxidle:最大空闲数量
minidel:最小空闲数量
3)读取配置文件
InputStream inputstream = 当前类.class.getClassLoader().getResourceAsStream("xxx.properties");
4)创建属性集合列表
Properties prop = new Properties();
prop.load(inputStream);
5)获取数据源---DruidDataSourceFactory
//public static DataSource createDataSource(Properties prop)
DataSources ds = DruidDataSourceFactory.createDataSource(prop);
//DataSource 替代了 DriverManager:Connection getConnection();
6)获取连接对象
Connection conn = ds.getConnection();
//使用连接对象
封装JDBC工具库,加入数据库连接池以及ThreadLocal的步骤
//为了模拟真实场景:一个线程使用自己的连接对象---操作数据库
class DruidJdbcUtils{
//声明一个DataSource类型的成员变量
private static DataSource ds; //数据源
private static ThreadLocal<Connection>t1 = new ThreadLocal<>();//当前线程对象
//无参构造私有化:目的外界不能new对象了
private DruidJdbcUtils(){}
//静态代码块
static{
//1)需要读取连接池的配置文件
//创建属性集合列表
Propertirs prop = new Properties();
//获取连接池配置文件的所在的输入流对象
InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
//将资源输入流加载到属性列表中
prop.load(inputStream);
//2)获取数据源---给成员变量ds赋值
//使用德鲁伊的工厂
ds=DruidDataSourceFactory.createDataSource(prop);
}
//封装一个功能:获取数据源
public static DataSource getDataSource(){
return ds;
}
//封装:获取连接对象的功能
public static Connection getConnection(){
//首先:从当前线程中获取连接对象
Connection conn=t1.get();
if(conn==null){
//当前线程持有连接对象
//从数据源:连接池中获取
conn=ds.getConnection();
//将连接对象绑定到当前线程中
t1.set(conn);
}
return conn;
}
//关闭资源---是否conn对象---close()--->t1.remove(解绑);从当前线程中解绑
}
commons-dbutils的使用
commons-dbutils的官网地址:Apache组织机构旗下的开源的工具类库
DbUtils – JDBC Utility Component
就是被用来完成JDBC操作,简化了JDBC操作的一种书写格式(查询多条记录,将这些记录封装List中)
针对原生JDBC的建议封装
完成JDBC操作
使用步骤:
1)需要导入核心的jar包 commons-dbutils.jar
mysql驱动jar包
连接池--druid的jar包
junit单元测试:核心包junit.jar以及依赖包
2)有关commons-dbutils.jar 核心接口以及核心类有哪些
使用的执行对象:操作数据库
org.apache.commons.dbutils.QueryRunner 里面封装就是PreparedStatement
QueryRunner:commons-dbutils.jar包所提供的QueryRunner类,是针对数据库连接池的使用,一方面解决了数据库访问过多时造成数据库承受的压力,另一方面也简化了数据查询
两个通用的方法
query(xxx,ResultSetHandler rsh):针对dql语句来完成查询操作
update(xxx,xx):针对dml语句操作:insert into,update,delete from...
核心接口:ResultSetHandler:针对结果集的处理
部分实现类
BeanListHandler:可以将查询的多条记录封装到List集合中
BeanHandler:将查询的结果集中某条记录封装到一个Java实体类中
ScalarHandler:查询出的单行单列的数据---查询出总记录数
聚合函数:select count(id字段)from 表名;---封装到Object对象中
JDBC事务管理
为什么需要管理事务?
当同时执行多条sql,中间如果存在异常,第一条语句成功了,第二条语句可能会失败导致业务风险
使用JDBC控制事务
1)利用SQL语句管理事务
start transaction--开启事务,这条语句之后的sql语句将处在一个事务当中,这些sql语句并不会立即执行
Commit--提交事务,一旦提交事务,事务中的所有sql语句才会执行
Rollback--回滚事务,将之前所有的sql取消
2)JDBC控制事务语句
Connection.setAutoCommit(false); //相当于start transaction
Connection.rollback(); rollback
Connection.commit(); commit
public class JDBCTransactionDemo {
public static void main(String[] args) {
//声明Connection类型变量
Connection connection = null ;
PreparedStatement ps = null ;
PreparedStatement ps2 = null ;
try {
//没有通过jdbc管理事务-----当同时执行多条sql,中间如果存在异常,第一条件语句成功了,第二条数据失败;
// 转账业务失败----->应该在jdbc操作转账的业务中加入事务操作!
//使用JDBC控制事务---->通过获取连接对象之后,加入事务的方法
//通过工具类获取连接对象
connection = DruidJdbcUtils.getConnection();
//开启事务---->利用Connection的功能void setAutoCommit(boolean autoCommit):默认自动提交
//参数为false:禁止自动提交,需要手动提交事务
connection.setAutoCommit(false);
//准备sql---参数化sql
String sql = "update account set balance=balance-? where id=? ";
//获取预编译对象
ps = connection.preparStatement(sql);
//参数赋值
ps.setInt(1.500);
ps.setInt(2,1);
String sql2 = "update account set balance = balance + ? where id = ?";
//获取预编译对象
ps2 = connection.preparStatement(sql2);
ps2.setInt(1,500);
ps2.setInt(2,2);
//分别执行更新操作
int count = ps.executeUpdate();
int i = 10/0 ;
int count2 = ps2.executeUpdate();
System.out.println(count+"---"+count2);
//提交事务: 如果没有问题,提交事务---数据在能永久更新
//Connection对象的方法:void commit()
} catch (Exception e) {
System.out.println("执行catch语句");
//出现异常,程序执行catch语句
//事务回滚
//连接对象的方法void rollback():回滚到默认在更新之前的操作
try {
connection.rollback() ;
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
/*System.out.println("异常抛出了");*/
}finally {
//任何情况下finally中的代码一定会执行的,除非 只执行这个语句之前,jvm退出了 System.exit(0) ;
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
}
//释放资源
DruidJdbcUtils.close(ps,connection);
DruidJdbcUtils.close(ps2,connection);
}
}
}