一、JDBC

1.简介

JDBC是一套标准,是Java与各大数据库厂商共同定制的一套接口. 这套接口由各大数据库厂商进行了实现.

2.使用步骤

  1. 1. 引入jar文件.
  2. 2. 加载数据库驱动 (JavaSE项目中可以省略 , JavaWeb项目必须编写此步骤)
  3. Class.forName("com.mysql.jdbc.Driver");
  4. 3. 通过驱动管理器, 获取JDBC连接对象.
  5. Connection conn = DriverManager.getConnection("数据库连接地址","帐号","密码");
  6. // 数据库连接地址格式: 主协议:子协议://ip地址:端口号/数据库名称
  7. // mysql的连接地址: jdbc:mysql://localhost:3306/java35
  8. // oracle的连接地址: jdbc:oracle:thin:@localhost:1521:ORCL
  9. 4. 通过连接对象, 创建SQL执行对象 (SQL执行环境)
  10. Statement state = conn.createStatement();
  11. 5. 通过SQL执行对象 ,执行SQL语句.
  12. state.execute(String sql语句);
  13. 6. 释放资源
  14. state.close();
  15. conn.close();

3.JDBC中常用的类型与方法

  1. 1. DriverManager : 驱动管理器
  2. 常用方法:
  3. - 获取数据库连接:
  4. static Connection getConnection(String 数据库地址,String 账号 ,String
  5. 码)
  6. 2. Connection : 数据库连接对象
  7. 常用方法:
  8. - 创建SQL执行对象: Statement createStatement();
  9. 3. Statement : SQL执行对象
  10. 常用方法:
  11. - 执行SQL语句(查询语句返回true, 其它语句返回false)
  12. boolean execute(String sql);
  13. - 执行DML语句(INSERT UPDATE DELETE) DDL语句(create alter drop)
  14. (返回int值, 表示语句对数据库表格的影响行数 !)
  15. (通常我们认为 返回值>0 表示执行成功.)
  16. int executeUpdate(String sql);
  17. - 执行DQL语句 (select)
  18. ResultSet executeQuery(String sql);
  19. 4. ResultSet : 结果集对象 (指的是一个select语句的查询结果)
  20. 常用方法:
  21. 1. 控制游标移动的常用方法:
  22. - boolean next() ****
  23. 作用: 控制游标向下一行移动.
  24. 返回值: 移动成功返回true , 下一行不存在移动失败, 返回
  25. false
  26. - boolean privious() 了解
  27. 作用: 控制游标向上一行移动.
  28. 返回值: 移动成功返回true , 上一行不存在移动失败, 返回
  29. false
  30. - boolean absolute(int 行号) 了解
  31. 作用: 控制游标向指定行移动
  32. 返回值: 移动成功返回true , 行不存在移动失败, 返回false
  33. - boolean beforeFirst() 了解
  34. 作用: 控制游标移动到第一行
  35. 返回值: 移动成功返回true, 没有第一行数据返回false
  36. - boolean afterLast() 了解
  37. 作用: 控制游标移动到最后一行
  38. 返回值: 移动成功返回true, 没有最后一行数据返回false
  39. 2. 获取游标指向行的字段值的常用方法:
  40. - XXX getXXX(String 列名) ***
  41. 根据字段名, 得到此字段的值
  42. - XXX getXXX(int 字段的索引) *
  43. 根据字段的索引, 得到字段的值 , 索引从1开始

二、工厂方法设计模式 ( 静态工厂方法模式 )

1.定义

工厂方法模式一种创建对象的模式.
工厂方法模式基于”输入”,应用在超类和多个子类之间的情况,这种模式将创建对象的责任转移到工厂类。

2.工厂设计模式的优点:

(1)面向接口编程,体现了面向对象的思想
(2)降低了耦合, 将创建对象的工作转移到了工厂类

3.代码案例


  1. 1. 水果接口
  2. public interface Fruit {
  3. void eat();
  4. }
  5. 2. 苹果 (水果的一种)
  6. public class Apple implements Fruit{
  7. @Override
  8. public void eat() {
  9. System.out.println("苹果吃起来甜甜的脆脆的.");
  10. }
  11. }
  12. 3. 香蕉 (水果的一种)
  13. public class Banana implements Fruit{
  14. @Override
  15. public void eat() {
  16. System.out.println("香蕉吃起来软软的甜甜的");
  17. }
  18. }
  19. 4. 静态工厂类
  20. public class FruitFactory {
  21. public static Fruit get(){
  22. //return new Apple();
  23. return new Banana();
  24. }
  25. }

三、DAO

1.定义

DAO(Data Access Object)是一个数据访问接口,数据访问:顾名思义就是与数据库打交道。夹在业务
逻辑与数据库资源中间。为了建立一个健壮的Java应用,应该将所有对数据源的访问操作抽象封装在一个公共API中。

2.DAO实现有所需组件

DAO模式是标准的JavaEE设计模式之一.开发人员使用这个模式把底层的数据访问操作和上层的商务逻辑分
开.一个典型的DAO实现有下列几个组件:
1. 一个DAO工厂类;
2. 一个DAO接口;
3. 至少一个实现DAO接口的具体类;
4. 数据传递对象(有些时候叫做Bean对象)
DAO 接口:

  1. public interface PetDao {
  2. /**
  3. * 查询所有宠物
  4. */
  5. List<Pet> findAllPets() throws Exception;
  6. }

DAO 实现类:

  1. public class PetDaoImpl extends BaseDao implements PetDao {
  2. /**
  3. * 查询所有宠物
  4. */
  5. public List<Pet> findAllPets() throws Exception {
  6. Connection conn=BaseDao.getConnection();
  7. String sql="select * from pet";
  8. PreparedStatement stmt= conn.prepareStatement(sql);
  9. ResultSet rs= stmt.executeQuery();
  10. List<Pet> petList=new ArrayList<Pet>();
  11. while(rs.next()) {
  12. Pet pet=new Pet(
  13. rs.getInt("id"),
  14. rs.getInt("owner_id"),
  15. rs.getInt("store_id"),
  16. rs.getString("name"),
  17. rs.getString("type_name"),
  18. rs.getInt("health"),
  19. rs.getInt("love"),
  20. rs.getDate("birthday")
  21. );
  22. petList.add(pet);
  23. }
  24. BaseDao.closeAll(conn, stmt, rs);
  25. return petList;
  26. }
  27. }
  28. 宠物实体类(里面get/set方法就不列出了)
  29. public class Pet {
  30. private Integer id;
  31. private Integer ownerId; //主人ID
  32. private Integer storeId; //商店ID
  33. private String name; //姓名
  34. private String typeName; //类型
  35. private int health; //健康值
  36. private int love; //爱心值
  37. private Date birthday; //生日
  38. }

四、SQL注入问题

1.问题描述

  1. 进行用户登录时, 输入不存在的帐号 如下的密码:
  2. 1' or '1'='1
  3. 结果显示登录成功.
  4. 因为用户输入的密码, 与我们的查询语句拼接后, 使得我们的查询语句产生了歧义:
  5. 原查询语句:
  6. select * from xzk_user where username='' and password='密码'
  7. 拼接后:
  8. select * from xzk_user where username='hahahaheiheihei' and password='1' or '1'='1'

2.解决sql注入问题

我们可以将SQL语句与参数分离,将参数作为SQL的特殊部分进行预处理. :(PreparedStatement 预编译)

3.PreparedStatement 预编译的SQL执行环境

3.1内部实现原理:

(1)将未拼接参数的SQL语句, 作为SQL指令, 先传递给数据库 进行编译.
(2)再将参数传递给数据库, 此时传递的参数不会再作为指令执行, 只会被当作文本存在.

3.2操作流程

  1. 操作流程与Statement基本一致:
  2. 1. 如何得到一个PreparedStatement 对象
  3. PreparedStatement state = conn.prepareStatement("预编译的SQL语句");
  4. 2. 预编译的SQL语句如何编写
  5. 需要填充参数的位置, 使用?代替即可! 例如:
  6. select id from xzk_user where username=? and password=?
  7. 3. 参数如何填充
  8. state.setXXX(int index,XXX value);
  9. setXXXXXX指的是数据类型,
  10. 参数1: index : SQL语句中?的索引值 , 1开始
  11. 参数2: value : 填充的参数值.
  12. 4. 如何执行填充完毕参数的SQL
  13. - boolean execute();
  14. - int executeUpdate();
  15. - ResultSet executeQuery();

3.3面试可能问道PreparedStatement与Statement谁的性能高?

  1. 看是什么数据库
  2. mysql中, preparedStatement原理是拼接SQL, 所以Statement性能高.
  3. Oracle中, preparedStatement原理是对SQL指令进行预处理, 再传递的参数不具备特殊含义.有更好
  4. SQL缓存策略,PreparedStatement高.

四、事务

1.概述:

将多条SQL语句, 看作一个整体. 要么一起成功, 要么一起失败.
事务在mysql中, 是默认自动提交的 .

2.在mysql操作方式1

  1. - 开启事务: start transaction;
  2. - 回滚 : rollback; --此次事务中所有的sql操作, 放弃.
  3. - 提交 : commit; --此次事务中所有的sql操作, 作为一个整体, 提交.

3.在Java操作方式2

  1. JDBC事务通过连接对象开启, 回滚 ,提交. 只针对当前连接对象生效.
  2. - 开启事务: conn.setAutoCommit(false);
  3. - 回滚事务: conn.rollback();
  4. - 提交事务: conn.commit();

4.事务面试题

  1. 1. 请描述事务的四大特征 :
  2. <1>. 原子性: 事务是一个整体 , 不可分割 , 要么同时成功, 要么同时失败.
  3. <2>. 持久性: 当事务提交或回滚后, 数据库会持久化的保存数据.
  4. <3>. 隔离性: 多个事务之间, 隔离开, 相互独立.
  5. <4>. 一致性: 事务操作的前后 , 数据总量不变 (例如: 转账时: 孟亮给帅兵转账是
  6. 一个事务, 转账完毕后. 两人余额的和不变.)
  7. 2. 请描述什么是脏读, 幻读, 不可重复读 ?
  8. - 脏读: 读取到了一个事务 未提交的数据.
  9. - 不可重复读: 一个事务中, 两次连续的读取 ,结果不一致(中间被其它事务更改了).
  10. - 幻读: 一个事务A在执行DML语句时, 另一个事务B也在执行DML语句 , B修改了A修改过的
  11. 数据, 导致A在查询时就像发生了幻觉一样(A更改的内容A看不到了.)
  12. 3. 请描述事务的隔离级别
  13. //三种级别锁: 页级,表级,行级(共享锁,排它锁).
  14. 1. 读未提交 : read uncommitted; (可能产生:脏读, 不可重复读, 幻读)
  15. 2. 读已提交 : read committed; (可能产生: 不可重复度, 幻读)
  16. 3. 可重复读 : repeatable read;(mysql默认值) (可能产生: 幻读)
  17. 4. 串行化 : serializable;
  18. - 查看数据库当前的隔离级别: select @@tx_isolation; (了解)
  19. - 数据库设置隔离级别: set global transaction isolation level 级别字符串;

五、批处理

1.批处理的原理:

将多条SQL语句, 转换为一个SQL指令. 显著的提高大量SQL语句执行时的数据库性能.

2.Statement对象使用流程:

  1. 1. 得到Statement对象
  2. Statement state = conn.createStatement();
  3. 2. 将一条SQL语句, 加入到批处理中.
  4. state.addBatch(String sql);
  5. 3. 执行批处理
  6. state.executeBatch();
  7. 4. 清空批处理
  8. state.clearBatch();

3.PreparedStatement对象使用流程:

  1. 1. 得到PreparedStatement对象
  2. PreparedStatement state = conn.prepareStatement("预编译的SQL");
  3. 2. 填充预编译的参数
  4. state.setXXX(1,填充参数);
  5. 3. 将一条填充完毕参数的SQL, 加入到批处理中.
  6. state.addBatch();
  7. 4. 执行批处理
  8. state.executeBatch();
  9. 5. 清空批处理
  10. state.clearBatch();

六、连接池(DataSource)

连接池用于缓存连接!

1.Properties 作为连接池配置文件

  1. Properties Java中的Map集合的实现类.
  2. .properties文件 用于通过文件描述一组键值对!
  3. .properties文件 ,可以快速的转换为Properties类的对象.
  4. 文件中内容的格式:
  5. 文件内容都是字符串 , 键与值之间通过等号连接 , 多个键值对之间换行分割.
  6. 例如:
  7. url=xxx
  8. user=xxx
  9. password=xxx
  10. 如何将文件 转换为 集合:
  11. 步骤:
  12. 1. 创建Properties对象
  13. Properties ppt = new Properties();
  14. 2. 创建一个字节输入流 , 指向.properties文件
  15. InputStream is = new FileInputStream("文件地址");
  16. 3. 将字节输入流, 传递给properties对象, 进行加载.
  17. ppt.load(is);

2.dbcp.properties的配置内容

druid.properties配置内容与其一样

  1. #数据库地址
  2. url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
  3. #数据库驱动类的名称
  4. driverClassName=com.mysql.jdbc.Driver
  5. #数据库账号
  6. username=root
  7. #数据库密码
  8. password=123
  9. #初始化连接池时,创建的连接数量
  10. initialSize=5
  11. #连接池的最大连接容量
  12. maxActive=20
  13. #空闲时允许保留的最大连接数量
  14. maxIdle=5
  15. #空闲时允许保留的最小连接数量
  16. minIdle=5
  17. #排队等候的时间
  18. maxWait=3000

3.连接池(DataSource)的使用

  1. 当我们需要使用连接时, 可以不用再创建连接 ! 可以直接从连接池中获取连接.
  2. 当连接池中存在空闲连接时, 会将空闲连接给到程序使用.
  3. 当连接池中不存在空闲连接时, 且连接池未满时 , 则创建连接提供给程序使用 ,并在程序使用完毕后,
  4. 缓存连接.
  5. 当连接池中不存在空闲连接时, 且连接池已满时 , 则排队等候空闲连接的出现.

注意:
使用连接池中的连接对象操作数据库时, 操作完毕依然需要释放连接(调用close()).
连接池中的连接在设计时, 使用了动态代理设计模式+装饰者设计模式 . 我们调用它的close方法,
代理没有关闭这个连接, 而是将连接重新放入了池中.

4.DBCP连接池的使用步骤

  1. 1. 引入相关的jar文件
  2. - dbcp.jar
  3. - poll.jar
  4. 2. 将配置文件引入
  5. 3. 将配置文件, 转换为Properties对象
  6. Properties ppt = new Properties();
  7. ppt.load(配置文件的输入流);
  8. 4. 通过连接池的工厂类(BasicDataSourceFactory)的创建连接池的方法(createDataSource())
  9. DataSource ds = BasicDataSourceFactory.createDataSource(ppt);
  10. 5. 从连接池中 获取连接对象
  11. Connection conn = ds.getConnection();

5.德鲁伊连接池的使用步骤

  1. 1. 引入相关的jar文件
  2. - druid-1.0.9.jar
  3. 2. 将配置文件引入
  4. 3. 将配置文件, 转换为Properties对象
  5. Properties ppt = new Properties();
  6. ppt.load(配置文件的输入流);
  7. 4. 通过连接池的工厂类(DruidDataSourceFactory)的创建连接池的方法(createDataSource())
  8. DataSource ds = DruidDataSourceFactory.createDataSource(ppt);
  9. 5. 从连接池中 获取连接对象
  10. Connection conn = ds.getConnection();

6.连接池工具类

通过把与连接池的操作封装成两个连接池工具类
6.1Druid

  1. public class DruidUtil{
  2. private static DataSource data = null;
  3. static {
  4. InputStream is =
  5. DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");
  6. Properties ppt = new Properties();
  7. try {
  8. ppt.load(is);
  9. data = DruidDataSourceFactory.createDataSource(ppt);
  10. } catch (Exception e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. /**
  15. * 用于从DBCP连接池中 获取一个连接
  16. * @return DBCP连接池中的一个连接对象.
  17. */
  18. public static Connection getConnection() {
  19. try {
  20. return data.getConnection();
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. return null;
  24. }
  25. }
  26. /**
  27. * 用于释放连接 , 执行环境 , 结果集 等资源
  28. * @param conn 要释放的连接资源
  29. * @param state 要释放的执行环境资源
  30. * @param result 要释放的结果集资源
  31. */
  32. public static void close(Connection conn,Statement state,ResultSet result) {
  33. if(result != null) {
  34. try {
  35. result.close();
  36. } catch (SQLException e) {
  37. // TODO Auto-generated catch block
  38. e.printStackTrace();
  39. }
  40. }
  41. if(state != null) {
  42. try {
  43. state.close();
  44. } catch (SQLException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. }
  49. if(conn != null) {
  50. try {
  51. conn.close();
  52. } catch (SQLException e) {
  53. // TODO Auto-generated catch block
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. }

6.2DBCP

  1. public class DBCPUtil{
  2. private static DataSource data = null;
  3. static {
  4. InputStream is =
  5. DBCPUtil.class.getClassLoader().getResourceAsStream("dbcp.properties");
  6. Properties ppt = new Properties();
  7. try {
  8. ppt.load(is);
  9. data = BasicDataSourceFactory.createDataSource(ppt);
  10. } catch (Exception e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. /**
  15. * 用于从DBCP连接池中 获取一个连接
  16. * @return DBCP连接池中的一个连接对象.
  17. */
  18. public static Connection getConnection() {
  19. try {
  20. return data.getConnection();
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. return null;
  24. }
  25. }
  26. /**
  27. * 用于释放连接 , 执行环境 , 结果集 等资源
  28. * @param conn 要释放的连接资源
  29. * @param state 要释放的执行环境资源
  30. * @param result 要释放的结果集资源
  31. */
  32. public static void close(Connection conn,Statement state,ResultSet result) {
  33. if(result != null) {
  34. try {
  35. result.close();
  36. } catch (SQLException e) {
  37. // TODO Auto-generated catch block
  38. e.printStackTrace();
  39. }
  40. }
  41. if(state != null) {
  42. try {
  43. state.close();
  44. } catch (SQLException e) {
  45. // TODO Auto-generated catch block
  46. e.printStackTrace();
  47. }
  48. }
  49. if(conn != null) {
  50. try {
  51. conn.close();
  52. } catch (SQLException e) {
  53. // TODO Auto-generated catch block
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. }