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)