JDBC原理图
导入jar包
连接方式1
连接方式2 反射获取Driver
方法3
方法4 Class.forname自动完成驱动注册(这种方式推荐)
driver底层有静态代码块在类加载的时候自动完成驱动注册
但是建议写上,更加明确
方法5
在方式4的基础上,使用配置文件,使连接更加灵活(推荐使用)
配置文件内容
结果集resultSet
简单理解为执行select返回的表
Statement
Statement对象,用于执行静态sql语句并返回其生成结果的对象
连接建立后需要对数据库进行访问,执行命名或sql语句,可以通过
Statement[存在sql注入]
PreparedStatement [预处理] (主要用这个开发应用)
CallableStatement[存储过程]
SQL注入
利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的sql语句段或命令,恶意攻击数据库
预处理查询
预处理dml
封装JDBCUtils工具类
public class JDBCUtils {
private static String user;
private static String password;
private static String url;
private static String driver;
static{
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\mysql.properties"));
user = properties.getProperty("user");
password = properties.getProperty("password");
url = properties.getProperty("url");
driver = properties.getProperty("driver");
} catch (IOException e) {
//实际开发中可以这样处理
//1,将编译异常转为运行异常
//2,这时调用者可以选择捕获异常,也可以选择默认处理该异常,比较方便
throw new RuntimeException(e);
}
}
//连接函数
public static Connection getconnection(){
try {
return DriverManager.getConnection(url,user,password);
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
//关闭函数
public static void close(ResultSet set, Connection connection, Statement statement){
try {
if(set != null){
set.close();
}
if(statement != null){
statement.close();
}
if(connection!=null){
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
测试
public class JDBCUtils_use {
public static void main(String []args) {
Connection connection = null;
//编写sql语句
String sql = "insert into admin values(?,?)";
PreparedStatement preparedStatement = null;
try {
//使用工具类获取连接
connection = JDBCUtils.getconnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,"Bob");
preparedStatement.setString(2,"123456");
int rows = preparedStatement.executeUpdate();
if(rows != 0){
System.out.println("插入成功~");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//使用工具类关闭连接
JDBCUtils.close(null,connection,preparedStatement);
}
}
}
执行成功,数据成功插入到数据库中
事务
例如用事务解决转账问题
connection.setAutoCommit(false);
connection.rollback();
connection.commit();
批处理
传统方法插入数据
批处理插入数据
addbatch()底层
数据库连接池
传统方式获取释放连接存在问题
数据库连接池
数据库连接池的种类
JDBC的数据库连接池通常使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由第三方实现
(1)C3P0 数据库连接池(hibernate,spring)
相对较慢,稳定性不错
(2)DBCP 数据库连接池
相对c3p0较快,不稳定
(3)Proxool数据库连接池
有监控连接池状态的功能,稳定性较c3p0差一点
(4)BoneCP
速度快
(5)Druid 阿里提供的数据库连接池
集DBCP,C3P0,Proxool优点于一身
C2P0数据库连接池方式一
方式二 使用配置文件来完成
long STATT = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = comboPooledDataSource.getConnection();
//System.out.println("连接成功~~");
connection.close();
}
long END = System.currentTimeMillis();
System.out.println("C3P0的5000耗时 "+(END-STATT));
Druid连接池(德鲁伊)
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));
//使用配置文件获得连接池
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
System.out.println("开始测试~");
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++) {
Connection connection = dataSource.getConnection();
// System.out.println("获取连接成功~");
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("druid 5000次耗费时间 "+(end-start));
发现5000次连接并不能体现出Druid的优势,反而比C3P0更慢
于是将连接数扩展到500000次
long STATT = System.currentTimeMillis();
for (int i = 0; i < 500000; i++) {
Connection connection = comboPooledDataSource.getConnection();
// System.out.println("连接成功~~");
connection.close();
}
long END = System.currentTimeMillis();
System.out.println("C3P0的500000次连接耗时 "+(END-STATT));
long start = System.currentTimeMillis();
for (int i = 0; i < 500000; i++) {
Connection connection = dataSource.getConnection();
// System.out.println("获取连接成功~");
connection.close();
}
long end = System.currentTimeMillis();
System.out.println("druid 500000次耗费时间 "+(end-start));
此时体现出druid的性能,实际开发推荐使用Druid
jdbcutilsbydruid:
public class JDBCUtilsbyDruid {
private static DataSource dataSource;
static{
try {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
//编写连接函数
public static Connection getconnection() throws SQLException {
return dataSource.getConnection();
}
//编写关闭函数
public static void close(ResultSet resultSet, Statement statement,Connection connection){
try {
if(resultSet != null){
resultSet.close();
}
if(statement != null){
statement.close();
}
if(connection != null){
//此处的连接关闭并没有实际关闭与数据库的连接,仅仅是将连接池的引用断开
connection.close();
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
这里的close方法与前面JDBCutils中的close是不同的,此处的close方法断开的是Druid实现的connection,并不是真正的与数据库连接的connnection,二者本质上实现类不同,Connection只是个接口
(运行类型不同)
ApDBUtils
通过将数据库内返回的结果集数据封装到list,可以在连接关闭后复用数据
Apache-DBUtils
public void testDbutils() throws SQLException {
//测试DButils,使用Druid连接池
//1.获取连接
Connection connection = JDBCUtilsbyDruid.getconnection();
//2.引入DButils相关的jar包
//3.创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
//4.执行相关的方法,返回Arraylist结果集
String sql = "select * from account";
/**
* 老韩解读
* (1)query方法就是执行sql语句,返回Resultset结果集,封装到Arraylist中
* (2)返回集合
* (3)Connection :连接
* (4)sql:要执行的sql语句
* (5)new BeanListHandler<>(account.class) 在将Resultset取出后->account对象->封装到Arraylist
* 过程中底层需要通过反射查看account类里有哪些属性,然后进行封装
* (6) 1 就是给sql语句中的?赋值的,是一个可变参数的
* (7)底层得到的resultset会在 query关闭,且PreparedStatement也会关闭
*/
List<account> list = queryRunner.query(connection, sql, new BeanListHandler<>(account.class));
System.out.println("输出集合信息");
for(account ac : list){
System.out.println(ac);
}
//释放资源
JDBCUtilsbyDruid.close(null,null,connection);
}
输出集合信息
account{id=1, name='马云', balance=2800.0}
account{id=2, name='马化腾', balance=10100.0}
查询单行数据使用的handler
查询结果是单行单列,返回Object.使用的handler
dbutils + druid 执行 dml语句
@Test
public void testDML() throws SQLException {
//测试DButils,使用Druid连接池
//1.获取连接
Connection connection = JDBCUtilsbyDruid.getconnection();
//2.引入DButils相关的jar包
//3.创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql = "UPDATE account set name ='王健林'where id = 1" ;
//返回值为执行后受影响的行数
int Affectedrows = queryRunner.update(connection, sql);
if(Affectedrows>0){
System.out.println("更新成功");
}
JDBCUtilsbyDruid.close(null,null,connection);
}
public void testDML() throws SQLException {
//测试DButils,使用Druid连接池
//1.获取连接
Connection connection = JDBCUtilsbyDruid.getconnection();
//2.引入DButils相关的jar包
//3.创建QueryRunner
QueryRunner queryRunner = new QueryRunner();
String sql = "insert into account values(null,?,?)" ;
//返回值为执行后受影响的行数
int Affectedrows = queryRunner.update(connection, sql,"许家印",10000);
if(Affectedrows>0){
System.out.println("插入成功");
}
JDBCUtilsbyDruid.close(null,null,connection);
}
BasicDao
Dao(Data access object)