回顾
1 DCL
修改自己密码
-- 格式 set password for '用户名'@'主机名'=password('新密码');
2 JDBC
JDBC是一套关系型数据库的规范(接口),我们程序员只需要掌握接口的方法即可
驱动:实现类由数据库厂商提供(jar)
JDBC基本操作
面向对象编程
面向接口编程(JDBC)
面向切面编程(spring)
面向服务编程(项目一、项目二)
// 获取连接 Class.forName("com.mysql.jdbc.Driver"); connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/db_day04","root","root"); // 创建语句执行者 statement = connection.createStatement(); // 编写sql String sql = "select * from user;"; // 执行sql并返回结果 resultSet = statement.executeQuery(sql); // 处理结果 While(resultSet.next()){// 指针下移,并判断是否有记录 true | false // key(列名) =value(当前行对应的值) resultSet.getXxx(int 第几列,String 列名称) getString(); 直接接收任意类型-----底层强转 } // 关闭资源 resultSet.close(); statement.close(); connection.close();
JDBC工具类
我们把JDBC操作的代码公共部分进行抽取,简化代码,提高效率
JDBC事务操作
通过Connection获取
// 手动提交事务 (把自动提交关闭---mysql数据库一条sql一个事务) public void setAutoCommit(boolean false); // catch public void rollback(); // try public void commit();
JDBC连接池&动态代理
1 PreparedStatement【掌握】
1.1 回顾上次登录案例
不输入密码一样可以登录成功!!!!!
问题
SELECT * FROM USER WHERE username = 'admin '#' and password = 'banzhanganlianbanzhuren'
我们将用户输入的实际参数和sql字符串进行了拼接,发送给数据库先编译后执行,改变了sql原有的意义,我们称为sql注入
1.2 解决方案
我们不能把用户输入的实际参数和sql字符串进行了拼接,就要使用PreparedStatement对象来优化,处理sql注入
1.3 API介绍
通过Connection获取
String sql ="select * from user where username =? and password =? " public PreparedStatement prepareStatement(sql);
设置参数
// 支持java所有类型 public void setXxx(int 第几个问号,Object 实际参数); int double String Object //万能
执行方法
// sql public boolean execute(); // dml public int executeUpdate(); // dql public ResultSet executeQuery();
1.4 解决登录案例
参考:com.itheima.a_logindemo.LoginDemoPlus
1.5 优点
-
防止sql注入,提高安全
-
减少sql编译次数,提高效率
-
参数与sql字符串分离,提高程序可读性
1.6 实现增删改查
步骤分析
// 获取连接
// 编写sql
// 创建预编译语句执行者
// 设置参数
// 执行sql并返回结果
// 处理结果
// 关闭资源
新增
// 新增 @Test public void test01() throws Exception { // 获取连接 Connection connection = JDBCUtilsPlus.getConnection(); // 编写sql String sql = "insert into user values(null,?,?);"; // 创建预编译语句执行者 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 设置参数 preparedStatement.setObject(1, "rose"); preparedStatement.setObject(2, "123"); // 执行sql并返回结果 int i = preparedStatement.executeUpdate(); // 处理结果 System.out.println(i); // 关闭资源 JDBCUtilsPlus.closeResource(preparedStatement, connection); }
修改
// 修改 @Test public void test02() throws Exception { // 获取连接 Connection connection = JDBCUtilsPlus.getConnection(); // 编写sql String sql = "update user set password=? where id = ?;"; // 创建预编译语句执行者 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 设置参数 preparedStatement.setString(1, "667788"); preparedStatement.setInt(2, 5); // 执行sql并返回结果 int i = preparedStatement.executeUpdate(); // 处理结果 System.out.println(i); // 设置参数 preparedStatement.setString(1, "112233"); preparedStatement.setInt(2, 2); // 执行sql并返回结果 i = preparedStatement.executeUpdate(); // 处理结果 System.out.println(i); // 关闭资源 JDBCUtilsPlus.closeResource(preparedStatement, connection); }
删除
// 删除 @Test public void test03() throws Exception { // 获取连接 Connection connection = JDBCUtilsPlus.getConnection(); // 编写sql String sql = "delete from user where id = ?"; // 创建预编译语句执行者 PreparedStatement preparedStatement = connection.prepareStatement(sql); // 设置参数 preparedStatement.setInt(1, 5); // 执行sql并返回结果 int i = preparedStatement.executeUpdate(); // 处理结果 System.out.println(i); // 关闭资源 JDBCUtilsPlus.closeResource(preparedStatement, connection); }
查询
课下作业
2 连接池【掌握】
2.1 概述
我们这二天使用JDBC操作每次都要创建连接、关闭连接,它是消耗资源和时间的,我们再项目初始化时创建一个池子,存放连接,再次使用连接时从池中获得,使用完毕后归还到连接池,提高连接的复用性,减轻服务器压力
DataSource
它是java对数据库连接池提供的一套规范(接口),我们程序员只需要掌握接口的使用方法,实现类由连接池厂商提供
2.2 c3p0
c3p0是一个开源连接池,目前hibernate等框架默认推荐使用
a)硬编码【了解】
步骤分析
1 导入jar包
2 编写代码
// 创建连接池对象
// 设置参数
// 获取连接
// 归还连接
b)配置文件【掌握】
步骤分析
1 导入jar包
2 定义一个配置文件
要求:
文件名:c3p0-config.xml
位置:src根目录下
3 编写代码
// 创建连接池对象
// 获取连接
// 归还连接
public static void main(String[] args) throws Exception { // 创建连接池对象 // ComboPooledDataSource() 会去src目录下 加载 c3p0-config.xml文件中的 <default-config> 配置信息 [推荐生产] // ComboPooledDataSource dataSource = new ComboPooledDataSource(); // ComboPooledDataSource("dev") 会去src目录下 加载 c3p0-config.xml文件中的 <named-config name ="dev">配置信息 ComboPooledDataSource dataSource = new ComboPooledDataSource("dev"); // 获取连接 Connection connection = dataSource.getConnection(); System.out.println(connection); // 归还连接 connection.close(); }
2.3 druid
Druid(德鲁伊)是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。
配置文件【掌握】
1 导入jar包
2 定义一个配置文件
推荐:
文件名:druid.properties
位置:src根目录下
3 编写代码
// 创建连接池对象
// 获取连接
// 归还连接
public static void main(String[] args) throws Exception { // 加载io流 InputStream is = DemoUse.class.getClassLoader().getResourceAsStream("druid.properties"); // 创建一个配置文件对象 Properties properties = new Properties(); properties.load(is); // 创建连接池对象 DataSource dataSource = DruidDataSourceFactory.createDataSource(properties); // 获取连接 Connection connection = dataSource.getConnection(); System.out.println(connection); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); connection.close();// 明确 close方法是归还到连接池,它是对JDBC底层close方法进行了拓展(增强) System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); System.out.println(dataSource.getConnection()); // 归还连接 }
2.4 连接池工具类【重要】
连接池是一个重量级对象,创建和销毁是非常非常非常消耗时间和资源,一般情况下一个项目初始化一次连接池,我们提到工具类,简化代码,提高效率
步骤分析
// 提供获取连接池的方法
// 提供获取连接的方法【常用】
// 提供归还连接 JDBCUtilsPlus(connection.clse()是归还连接池,而不是销毁对象)
3 动态代理【理解--框架使用】
刚才我们学习完了常用的连接池(Druid),我们知晓了如果连接需要归还给连接池,那么直接调用close方法即可。 但是我们在学习jdbc时调用connection.close() 是关闭连接,而现在是将连接还回连接池。这个是怎么做到的呢 ? 其实是对Connection的close方法进行了增强。
3.1 方法增强【理解】
a)继承
针对于目标类创建一个子类对象,重写父类的方法
不推荐使用
-
需要咱们自己写子类【麻烦】
-
java是单继承,会占用一个继承位
-
b)动态代理
代理模式
动态代理
在程序运行期间,由JVM虚拟机帮你创建代理类对象,我们可以对目标类方法进行增强
常用动态代理技术
JDK、 CGLIB、JAVA ASSIST
JDK动态代理(sun公司自身提供的):要求目标类必须是接口的实现,JVM虚拟机根据接口创建代理类对象
3.2 代理案例【了解】
需求分析
薇薇老师在出道前免费唱歌,出道后,有了经纪人,先收费后唱歌;
步骤分析
1 接口 singer
唱歌
吃饭
2 创建目标类 Weiwei
微微一笑很倾城
珍珠翡翠白玉汤
3 创建代理类对象---实现对目标方法(唱歌)增强
Proxy工具类
代码实现
// [了解] @Test public void test01() throws Exception { // 薇薇老师还未出道 栈内存 方法执行完毕 对象销毁 // 栈内存 (逃逸分析) 激发你们的潜质 如果在方法中 创建了一个对象 ,其他方法没用调用的话 此方法 在栈,方法执行完毕 对象就会立马销毁 Weiwei weiwei = new Weiwei(); // weiwei.sing(); // System.out.println(weiwei.eat()); // 薇薇老师出道了,对唱歌方法进行增强 Proxy jdk提供的工具类 /* * 参数一:目标类的加载器 * 参数二:目标类的实现接口数组(java是单继承,多实现) * 参数三:调用增强接口,实现对目标类方法增强的 * * */ Singer weiWeiProxy = (Singer) Proxy.newProxyInstance(weiwei.getClass().getClassLoader(), new Class[]{Singer.class}, new InvocationHandler() { // 具体增强的业务逻辑,都写在这里 /* * 参数一:代理对象本身 类似于 this * 参数二: 当前具体执行的方法 反射 * 参数三:调用方法传递的实际参数数组 可变参数的底层就是数组 * * */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("invoke执行了"); // 获取当前方法名 String name = method.getName(); if ("sing".equals(name)) { System.out.println("收费10000元。。。。"); } // 调用目标对象方法 实例在堆内存 Object invoke = method.invoke(weiwei, args); // 返回给调用者 return invoke; } }); // 调用代理类对象的方法 // weiWeiProxy.sing(); System.out.println(weiWeiProxy.eat()); }