目录

  • 1.内容介绍
  • 2. PreparedStatement查询
    • 2.1 回顾jdbc
    • 2.2 PreparedStatement的引入
      • 2.2.1 PreparedStatement介绍
    • 2.3 PreparedStatement使用
    • 2.4 完善功能
    • 2.5 为什么选择PreparedStatement
      • 2.5.1思路清楚,使用方便
      • 2.5.2 速度,效率更高,更快
      • 2.5.3 防SQL注入
    • 2.6小结
  • 3.完成登录功能-优化
    • 3.1 登录方式比较
    • 3.2 登录方式二实现
    • 3.3 小结
  • 4.细节功能-事务理论
    • 4.1事务
      • 4.1.1事务使用
      • 4.1.2 事务认识
    • 4.2 拿到主键(了解)
      • 4.2.1 为什么需要拿到Id
      • 4.2.2 Statement拿到主键的方式
      • 4.2.3 PreparedStatement 拿到主键的方式
    • 4.3 小结
  • 5.连接池
    • 5.1 连接池思想
    • 5.2 DBCP连接池实现
    • 5.3 抽取(了解)-工具
      • 5.4.1 抽取 (增,删,改方法)
    • 5.5 小结
  • 6.课程总结
    • 6.1 重点
    • 6.2 难点
    • 6.3 如何掌握
    • 6.4 排错技巧
  • 7.课后练习
  • 8.面试题
  • 9.扩展知识或课外阅读推荐

JDBC深入理解

1.内容介绍

1.PreparedStatement介绍(了解)
2.PreparedStatement使用(掌握)
3.登录方式介绍(掌握)
4.登录方式实现(掌握)
5.事务介绍(了解) 同生共死
6.事务认识(掌握)
7.事务使用(掌握)
8.拿到主键(了解) 认识一下[理解人家的框架(代码)可以做到]
9.连接池(理解)
10.抽取BaseDao:增删改,可以写成一个方法

2. PreparedStatement查询

2.1 回顾jdbc

通过jdbc完成一个增删改查
①建一个表student
字段 username,password,age,id,intro,sex
根据表创建一个域对象,domain对象
②写一个dao层,在里面写一个接口
IStudentDAO
③写一个dao层接口的实现类

④抽取代码JDBCUtil–工具类

完善查询所有:

2.2 PreparedStatement的引入

在使用JDBC的时候,定义sql的时候,里面有个很纠结的问题,拼接字符串不好拼接
,特别是插入和修改更不好拼接;

怎么才能不拼接字符串 – 通过PreparedStatement

2.2.1 PreparedStatement介绍

Statement: 表示静态SQL语句对象.sta.excuteUpadate(sql)
PreparedStatement:Statement的子接口,表示预编译SQL语句对象
Select * from student where id = ?
.PreparedStatement ps= conn.PreparedStatement(sql);
Ps.set(1,1)

什么是预编译SQL语句

预编译语句PreparedStatement 是java.sql中的一个接口,它是Statement的子接口。通过Statement对象执行SQL语句时,需要将SQL语句发送给DBMS,由 DBMS首先进行编译后再执行。预编译语句和Statement不同,在创建PreparedStatement 对象时就指定了SQL语句,该语句立即发送给DBMS进行编译。当该编译语句被执行时,DBMS直接运行编译后的SQL语句,而不需要像其他SQL语句那样首先将其编译,在执行。

Api示例:

注意: ?上面不要添加引号, 不要这样写 ‘?’;
后面会自动知道该?表示的是什么类型;

  比如:pstm.setInt(2,110592) 这里可以设置int值,它会自动知道;

2.3 PreparedStatement使用

贾琏欲执事:
但是其中的欲 — 获取欲处理对象

注意的地方:
mysql有个叫SQL_SAFE_UPDATES的变量,为了数据库更新操作的安全性
直接执行:SET SQL_SAFE_UPDATES=0; 缺省session 只针对当前会话有效
SET SQL_SAFE_UPDATES=1; 没有限制条件不能运行 限制条件为主键 当前会话
设置全局SET global SQL_SAFE_UPDATES=1;

①贾琏步骤都是一样,而PreparedStatement是Statement的子接口
②问号(?)–相当于占位符(SQL里面的问题),我们使用的时候有没有区分类型?–没有-字符串也不需要特殊加上引号
③在拿到语句对象的时候就使用SQL
Statement st = conn.createStatement();
PreparedStatement st = conn.prepareStatement(sql);//预编译sql
④在执行的时候不需要传sql;

⑤所有占位符,需要给它添加相应的值–
PreparedStatement对象.setXxxx(位置(从1开始),相应的值)
⑥? 只能放在特定的地方(不能替换关键字表名)–不能放在 select * from ?
PreparedStatement容易出错的地方:

1.占位符字符串千万不要加上引号;
2.加上相应的值的时候,位置,类型,个数必须要完全一致;
3.执行的时候,不要SQL放进来;
st.executeUpdate()执行的是编译之后的语句,如果你把sql放进去,是编译前的sql,里面就会出现问题;

总结: Statement 和 PreparedStatement的区别
Statement在创建语句对象,不需要传入sql;
statement = connection.createStatement();
PreparedStatement在创建预编译语句对象,在创建的时候,需要传入sql;
ps = connection.prepareStatement(sql);
在执行sql语句的时候,Statement 需要传入sql;PreparedStatement在执行sql语句时候,不需要传入sql;

2.4 完善功能

刚才是通过st.setString/st.setInt/setBoolean 等方式设置值,还要一个方法
st.setObject(index,value)来设置;
如下图:

完成插入功能:

完善删除功能

完成查询功能

使用Statement和使用PrepareStatement那种方式更好?
以后都使用PrepareStatement;

2.5 为什么选择PreparedStatement

以后都用PreparedStatement,它有以下这些好处;

2.5.1思路清楚,使用方便

不需要我们去拼接字符串
特别是字段很多的时候,如果用Statement拼字符串。谁用谁知道;

2.5.2 速度,效率更高,更快

PreparedStatemnt的速度比Statement更快
PrepareStatement是预处理语句

我把一条sql发送到数据库之后,数据库会做什么事情?

通过两块完成:Java程序和数据库部分

Java程序会发送sql到数据库:

Statement发送sql[会先检查数据库缓存是否有这个sql,有直接使用 ,有的数据库会缓存sql,有的不会,mysql没有缓存sql ]
到缓存区查看sql’是否存在,如果存在,直接使用缓存区的sql执行,如果不存在,从①到
⑤,这些步骤是很费时间和性能;

①检查sql的安全性;
②解析sql;
③将sql编译成二进制;
④执行sql;
⑤(有的数据库会把这条sql放到缓存中,也就是在数据库里面开辟一块缓存空间)

PreparedStatement 发生sql

Mysql不支持缓存

2.5.3 防SQL注入

直接使用登录功能来演示防此sql注入,登录功能一般怎么做?

代码实现:

测试代码:

这个就是sql注入;
分析:
String name = " ’ or 1=1 or ’ ";
当我们的name是上面的内容的时候,用Statement我们会去拚接字符串,就会出现下面一句sql:
select * from student where name=’’
or 1=1
or ’ ’ and password=‘werwer’
那么就肯定能查询到数据

PrepareStatement 不是拼接字符串,它是模板-- 格式是固定好的
但是使用PrepareStatement 它的语句相当是一个模板,这个模板的基本结构我们是不能够进行更改的(不能拚接字符串),于是,它很好的解决了sql注入的问题

2.6小结

1.PreparedStatement是什么
指的时候预编译语句对象 创建对象 就传入sql进行编译 在执行 不需要传入sql 直接运行
2.PreparedStatement实现
3.PreparedStatement和Statement区别
①PreparedStatement 不需要拼接字符串,结构清晰
②PreparedStatement效率比Statement高一点
③PreparedStatement可以防止sql注入

3.完成登录功能-优化

3.1 登录方式比较

完成简单登录功能:

传入的用户名和密码,然后拼接查询用户的SQL
Select * from 用户表 where name = ? and password = ?
如果用户名和密码同时存在,能查询到数据,然后我们就把这个数据封装成相应的对象,再把这个对象返回,如果用户名和密码错误,没有数据,直接返回null

登录方式比较:

3.2 登录方式二实现


测试:

3.3 小结

1.登录方式实现
①select * from user where username = ? and password=?
②select * from user where username=?
③select count(*) from user where username=? and password=?

上午小结
1.回顾 数据层,抽取工具,解决硬编码,排错
2.介绍PrepardStatement及基本使用
3.介绍PrepardStatement好处? 快,安全,简洁

4.分析登陆
(1)Username+password 验证对象方式1
(2)Username 验证对象及密码登陆方式2
(3)通过登陆方式一 演示sql注入
(4)通过登陆方式一解决sql注入

4.细节功能-事务理论

4.1事务

4.1.1事务使用

什么是事务?
事务: 程序里面的一组操作,要不都成功,要不都失败;
innodb 支持事务 myisam不支持事务
事务示例:
银行转帐功能: bank / money
过儿和姑姑:
过儿 : 10000块钱 姑姑 : 0块钱

转账:过儿要给姑姑转1000块钱
分析:转钱需要提供两条sql,但是程序员也会出错,比较代码写错了.

①update bank set money = money +1000 where name = ‘姑姑’
②代码出错
③update bank set money = money -1000 where name= ‘过儿’

完成示例:

事物的案例:
分析:①建表

   ②模拟问题出现

    出现问题,怎么来完成事务--同时提交或者同时失败③ setAutoCommit(boolean autoCommint) 将此链接的自动提交模式设置为给定状态,(设置自动提交事务,true的时候,自动启动,为false的时候,禁止自动启动)

在我们JDBC中,一直有事务存在,但是这个事务默认是自动提交(conn.getAutoCommit()等于true),当它是自动提交的时候,每执行一条sql,就提交事务,而刚两条sql,说明不是在一个事务里面,所以出问题了;

如何解决?–我们的事务一般来说,要设置成执行几条SQL(完成一个整体的功能,在进行提交),因此我们需要事务的自动提交修改false ,(不让它执行完一条sql,就自动提交) conn.setAutoCommint(false) --将自动提交关闭,设置手动提交

当我们把自动提交关闭,那sql就不是提交执行,于是我们一定要记住,当我们一个整体功能完成之后,自己要手动进行提交;-- conn.commit 但是失败之后,要记住数据回滚
conn.rollback()

                                                                  7.avi
4.1.2 事务认识

事务(Transaction,简写为tx):
在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。

为确保数据库中数据的一致性,数据的操纵应当是离散的成组的逻辑单元:
当每个逻辑操作单元全部完成时,数据的一致性可以保持,
而当这个单元中的一部分操作失败,整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。

事务的操作:先定义开始一个事务,然后对数据作修改操作,这时如果提交(commit),这些修改就永久地保存下来,如果回退(rollback),数据库管理系统将放弃您所作的所有修改而回到开始事务时的状态。
事务:一组操作在事务空间,要么都成功,要么都失败;


事务的ACID属性:
Atomic原子性、Consistency一致性、Isolation隔离性和Durability持久性。

原子性:指整个事务是不可以分割的工作单元。只有事务中所有的操作执行成功,才算整个事务成功,事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该回到执行事务前的状态。

一致性:指数据库事务不能破坏关系数据的完整性以及业务逻辑上的一致性。例如对于银行转账事务,不管事务成功还是失败,应该保证事务结束后两个转账账户的存款总额是与转账前一致的。

隔离性:指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。(Hibernate在讲) JPA 框架

持久性:指的是只要事务成功结束它对数据库所做的更新就必须永久保存下来。即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。


事务:是用户定义的一组操作。这组操作要么都做(都成功),要么都不做;
事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被提交(commit),要么整个事务回滚(rollback)到最初状态
处理事务的两个动作:
提交:commit: 当整个事务中,所有的逻辑单元都正常执行成功. ---->提交事务.—数据已经提交,不能更改.
回滚:rollback: 当整个事务中,有一个逻辑单元执行失败, ---->回滚事务.
撤销该事务中的所有操作—>恢复到最初的状态.


如何在代码中去处理事务:
1.在JDBC中,事务是默认提交的. 必须先设置事务为手动提交.
connection对象.setAutoCommit(false);//设置事务为手动提交.
2.手动的提交事务.
connection对象.commit();
3.若出现异常必须回滚事务:
不回滚事务,总余额依然是正确的. 若不回滚事务,不会释放数据库资源.
connection对象.rollback();


1.在JDBC在事务是默认提交的,那是在什么时候提交的.
在执行一个DML/DDL操作的时候,就已经提交事务了.
2.针对于CRUD操作. 只有DML操作才有事务,查询操作没有事务.
但是,我们一般会把查询也放在事务里面.—>Spring的事务管理的时候再讲.
3.以后,凡是发现自己编写的代码是正确的,测试也通过,但是就是数据库表中的数据不变----->事务没提交的问题. 等我们学习MyBatis开始就会遇到这个问题了
4.MySQL中,InnoDB支持外键.支持事务,MyISAM不支持外键,不支持事务.


至于事务的管理,在Hibernate,MyBatis,Spring还要再讲.
事务管理器:TransactionManager.

4.2 拿到主键(了解)

4.2.1 为什么需要拿到Id

现在我们插入的一条数据,但是并不知道该数据的id是多少, 而我们有时候操作,需要这个id.

比如我们向product表插入一条数据,它的数量为200,但是product表里面并没有表示数量的字段,而product_store表里面含有storeNum,所有我们应该在插入数据之后,同时需要插入一条数据到product_store表里面; – 这时候我们就需要拿到product表里新插入的id;

怎么取到Id值呢?
通过求表里面Id的最大值,获取到;–但是还是存在问题;比如多个人同时访问的时候,得到的Id也可能出现问题;


Statement.RETURN_GENERATED_KEYS

4.2.2 Statement拿到主键的方式

对于添加来说,里面通过连接对象 拿到语言对象,通过conn.createStatement()方式取得;
需要执行的时候 通过executeUpdate方法执行, 除了executeUpdate有一个参数以外,还有
一个方法executeUpdate(String sql,int autoGeneratedKeys);

自动生成键是否可以获取;(也就是自动生成的Id键,我们可以获取)


获取由于执行此Statement对象而创建所有自动生成的键

注意:

这里并没有指定列,但是这里只有一列,所有可以通过rs.getLong(1) 方式获取

4.2.3 PreparedStatement 拿到主键的方式

案例:
// 编写sql语句
String sql = “insert into bank (money,name) values (?,?)”;
// RETURN_GENERATED_KEYS 该常量指示生成的键应该可用于获取。
ps = connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
ps.setInt(1, 600);
ps.setString(2, “tom”);
ps.executeUpdate();
// getGeneratedKeys() 获取由于执行此 Statement 对象而创建的所有自动生成的键。
ResultSet rs = ps.getGeneratedKeys();
while(rs.next()){
System.out.println(“主键为:”+rs.getInt(1));
}
如何在JDBC中保存数据的时候获取自动生成的主键呢?


Statement:
int executeUpdate(String sql, int autoGeneratedKeys):
执行SQL:
参数:autoGeneratedKeys,是否需要返回自动生成的主键.常量值:Statement.RETURN_GENERATED_KEYS
ResultSet getGeneratedKeys():获取自动生成的主键

PreparedStatement:
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) :创建PreparedStatement对象,并指定是否需要返回生成的主键. 参数的常量值:Statement.RETURN_GENERATED_KEYS


单据和单据明细:


Hibernate中可以自动返回,(底层已经封装OK).

4.3 小结

总结:
事务:指一组操作,要么同时成功,要么同时失败;
事务的四个属性ACID:原子性,一致性,隔离性,持久性;

5.连接池

5.1 连接池思想

对于连接池,是偏理论的知识,需要掌握其中思想,不要求你们能写代码实现;
连接(connection)池: 就是用来装连接对象的容器;

为什么需要使用连接池?

一段Java代码操作数据库,需要取得连接,每次操作数据库都是需要取到一个连接,但是为什么不能用一个连接呢?–使用同一个连接,会存在线程安全的问题;
每次取到连接都需要验证用户名,密码;
问题:验证用户名和密码都需要时间吗?

假设每次验证都需要0.01s,但是我做了一个网站,同时有一千人访问,需要多少秒?
浪费10秒;
比如新浪首页,查询体育新闻,需要一条sql,查询娱乐新闻,需要一条sql,可能一个首页面,就会存在100多个请求(到数据库查询),那这样浪费多少秒?
浪费1000秒

结论:会浪费很多时间

每次请求都会创建一个connection,因此会浪费资源(内存),当同时1000人访问的时候,那就会占用很多资源,因此很浪费时间和容器操作系统崩溃;
最开始的时候就创建一些连接对象放到连接池中 请求来了可以直接在连接池中获取连接 操作数据库
操作完成以后 释放连接 回到连接池 等待下一次被请求使用
初始的时候 创建了一些连接 最小连接数 请求并发的时候 创建更多的连接 最大连接
线程池

怎么解决? --连接池

连接池:就是用来装连接对象的容器,池;
连接池里面的连接从哪里来,从数据库来;

取到连接池里面取到连接也需要用户名和密码,也需要时间,但是Java代码取到连接只需要从连接池里面拿到,不需要用户名和密码,用完之后,还回到连接池;

这个有点像 泡面,饿的时候,不需要每次都跑出去拿,在家里准备多一点就是;

但是这里会存在问题?
①连接池一出来就有连接嘛?
当然有,需要提前设置好连接数;
有的人用了会还回来,我下一个人在用就行了;

②如果我拿10个连接,你只有5个,怎么办?
不够的时候,又到数据库里面拿
但是现在,如果不够就到数据库拿,那我要连接池干嘛?
还是会浪费时间和资源,而且还多了中间一层;

③连接池如果放过多的连接,浪费,并且占用资源,对不对?

④如果5个人一直没有还,怎么办?
如果需要解决上面的问题,(需要研究一下火车站的问题)
不管有没有人,都需要留一个两个窗口,–有个初始窗口
1.初始容量(5)
火车站刚开始需要有几个窗口
2 如果人变多的时候,窗口不够怎么办—需要增加窗口,但是这个窗口不是随便增加
当人数比较多的时候,添加窗口;
最大数量(10)

3.如果人变少的时候,只有几个窗口 – 这时候需要最小窗口
最小数量(2)

4.如果有人占着窗口不放,怎么办?
一个人如果不是做正事,比如占了3分钟,不要占用窗口
最大连接时间(3)
5.票已经卖完的时候,还有人等待怎么办?
如果等待过长,断开连接,请求超时;

这就是连接池的理解;

连接池概述

在Java中,连接池使用javax.sql.DataSource接口来表示连接池. 这里的DataSource就是连接池。连接池就是DataSource

DataSource是接口,和JDBC一样,是Sun公司开发的一套接口,需要各大厂商实现;
需要导入相应包—导包…
所以使用连接池,首先需要导包;

常用的DataSource的实现有下面两种方式:
DBCP: Spring推荐的(Spring框架已经集成DBCP)
C3P0: Hibernate推荐的(早期)(Hibernate框架已经集成C3P0)持久层


使用连接池和不使用连接池的区别在哪里?

从代码上:
不使用连接池: Conenction对象由DriverManager获取.
Connection conn = DriverManager.getConnection(url,username,password);

使用连接池:(只有一个不同点,现在的连接需要从DataSource里面拿,DataSource需要从数据库拿,
所以我们需要把用户名和密码给连接池,连接池帮我们从数据库拿连接)
如何创建DataSource对象,如何在DataSource中设置url,账号,密码.
Connection conn = DataSource对象.getConnection();


最后使用连接池的时候,需要释放资源:
释放资源: Connection对象.close():
是把Connection放回给连接池,而不是和数据库断开.只是连接放回到连接池

5.2 DBCP连接池实现

上面已经提到实现连接池的方式,通过DBCP和C3P0的方式;
阿里的Druid
它的效果和JDBC的效果一样,看不出什么效果;

下面采用DBCP的方式来实现连接池
第一步 准备jar包:
拷贝jar:
commons-dbcp-1.3.jar commons-pool-1.5.6.jar .

导入包之后,不会用–
查阅文档: commons-dbcp-1.3-src\doc\BasicDataSourceExample.java(例子)

唯一的区别:获取连接方式不同
BasicDataSourceExample.java 取得连接

解决DBCP的硬编码问题:
应该把连接信息放到配置文件中去: 配置文件的名词可以任意.
但是配置文件中的key,必须是BasicDataSource对象的属性(setXxx方法决定的属性);

dbcp.properties
#连接字符串
url=jdbc:mysql://localhost:3306/jdbcdemo
#用户名
username=root
#密码
password=admin
#驱动的类路径
driverClassName=com.mysql.jdbc.Driver
#连接池启动时的初始值
initialSize=1
#连接池的最大值
maxActive=50
#连接池的最大空闲数
maxIdle=20


如何把dbcp.properties中的配置信息,设置到程序中去:


直接读取资源文件的方式:

注意:在db.properties里的属性名称必需要和这边的对应上
测试方法:

方式二: 通过BasicDataSourceFactory工厂
通过BasicDataSourceFactory工厂拿到连接:

注意:在db.properties里的属性名称必需要和这边的对应上,ds.setUsername的首字母小写;

注意

5.3 抽取(了解)-工具

5.4.1 抽取 (增,删,改方法)

抽取方式一:

① 写个类BaseDAOImpl JDBCUtils
写一个公共的方法 – 完成增加,删除,修改

①一个类BaseDAOImpl
②改写 增,删,改

5.5 小结

1.连接池是什么
装连接的容器
2.为什么要使用连接池
提高数据库的连接效率 节省内存资源,避免系统里面存在大量的连接数
3.连接池的思想
从连接池里面拿到连接 不用每次都从数据库拿到连接,结合火车站的示例
4.连接池的实现(理解)
DBCP(Spring) C3PO(hibernate)
5. 把增 删 改的方法 抽取一个公共的方法里面

6.课程总结

1.PreparedStatement:预编译对象:静态sql对象
安全

简洁

2.事务:同生共死:验证了很多的情况并且考虑数据库的存储引擎
//将事务改成手动提交
conn.setAutoCommit(false);
------一组操作的sql
conn.commit();
发生异常之后回滚事务
3.主键获取
(1)目的
(2)实际操作调用API关注用,关注概念,关注理解
(3)Statement 为什么这么考虑
4.连接池:理解,思想,会用!
5.抽取公共的增删改查

6.1 重点

1.认识PreparedStatement(预编译语句对象)
2.PreparedStatement使用
创建的对象时候,需要传入sql ,执行的时候 不需要传入sql
3.PreparedStatement和Statement区别
不用拼接字符串结构清晰 效率高 可用防此sql注入
4.登录方式比较
方式一 select * from user where username=’’ and password=’’;
方式二 select * from user where username=’’
方式三 select count(*) from user where username =’’ and password=’’(不考虑)
5.事务的特性ACID
事务:一组操作 要么都成功 要么都失败
原子性 一致性 隔离性 持久性
6.连接池思想掌握
连接池:装连接的容器 结合火车卖票例子
使用连接池 和不使用连接池的区别?
从用法上面区别 /从效率上的区别
使用连接池 --了解

6.2 难点

1.理解并且使用连接池思想
2.难点二:sql注入

6.3 如何掌握

1.多去敲上课老师的代码 敲一下(照着敲一票)
2.理论结合实现去掌握知识点

6.4 排错技巧

有报错情况:

1.出现不懂得异常之后,可以把异常信息拷贝到百度或者API里面搜索;
2.出现问题之后,报错信息 ,怎么看 自己写的代码 有没有问题
3.根据百度或者API里面信息去解决问题;

没有报错情况:
1.会根据解题思路 一步一步去排查
2.System.out.println();
3.debug模式 F8 直接运行下一个断点 F6 直接运行一句代码 F5 进入方法里面

7.课后练习

1.第一题:完成两种登录方法的登录
2.第二题: 模拟完成一个转账的功能(练习事务)
3.第三题: PrepareStatement 返回主键(选做)
4.第四题: 使用 DBCP完成一张表的crud
5.第五题(选做):如果一个项目中有多个实体类(domian包下面有多个类,例如学生,老师,用户,部门等),那么对应的dao下面也会有多个对应的接口和多个实现类。请先写出至少2个实体类的场景,然后考虑如何优化抽取dao层对应的接口和实现类

8.面试题

1.第一题 事务的特性有哪些
2.第二题 PreparedStatement和Statement的区别
3.第三题 使用连接池和不使用连接池的区别

9.扩展知识或课外阅读推荐

A029_jdbc深入理解相关推荐

  1. 通用解题法——回溯算法(理解+练习)

    积累算法经验,积累解题方法--回溯算法,你必须要掌握的解题方法! 什么是回溯算法呢? 回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就&quo ...

  2. stream流对象的理解及使用

    我的理解:用stream流式处理数据,将数据用一个一个方法去 . (点,即调用) 得到新的数据结果,可以一步达成. 有多种方式生成 Stream Source: 从 Collection 和数组 Co ...

  3. Linux shell 学习笔记(11)— 理解输入和输出(标准输入、输出、错误以及临时重定向和永久重定向)

    1. 理解输入和输出 1.1 标准文件描述符 Linux 系统将每个对象当作文件处理.这包括输入和输出进程.Linux 用文件描述符(file descriptor)来标识每个文件对象.文件描述符是一 ...

  4. java局部变量全局变量,实例变量的理解

    java局部变量全局变量,实例变量的理解 局部变量 可以理解为写在方法中的变量. public class Variable {//类变量static String name = "小明&q ...

  5. 智能文档理解:通用文档预训练模型

    预训练模型到底是什么,它是如何被应用在产品里,未来又有哪些机会和挑战? 预训练模型把迁移学习很好地用起来了,让我们感到眼前一亮.这和小孩子读书一样,一开始语文.数学.化学都学,读书.网上游戏等,在脑子 ...

  6. 熵,交叉熵,散度理解较为清晰

    20210511 https://blog.csdn.net/qq_35455503/article/details/105714287 交叉熵和散度 自己给自己编码肯定是最小的 其他的编码都会比这个 ...

  7. mapreduce理解_大数据

    map:对不同的数据进行同种操作 reduce:按keys 把数据规约到一起 看这篇文章请出去跑两圈,然后泡一壶茶,边喝茶,边看,看完你就对hadoop 与MapReduce的整体有所了解了. [前言 ...

  8. 文件句柄和文件描述符的区别和理解指针

    句柄是Windows用来标识被应用程序所建立或使用的对象的唯一整数,Windows使用各种各样的句柄标识诸如应用程序实例,窗口,控制,位图,GDI对象等等.Windows句柄有点象C语言中的文件句柄. ...

  9. 通俗理解条件熵-数学

    就是决策树里面选划分属性用到的计算 条件熵越小表示划分之后各个集合越纯净 前面我们总结了信息熵的概念通俗理解信息熵 - 知乎专栏,这次我们来理解一下条件熵. 我们首先知道信息熵是考虑该随机变量的所有可 ...

最新文章

  1. spring读取配置文件的几种方式
  2. 【转】Linux命令工具 top详解
  3. oracle日志备份少数据库,oracle 账号锁定日志Oracle数据库全量备份恢复和部分备份恢复...
  4. 解决cisco路由器cpu占用率100%问题
  5. Release Type
  6. HDU2089——不要62 (数位DP)
  7. 【flutter】学习之路(一)环境的搭建
  8. NLog日志框架使用探究
  9. linux磁盘写保护怎么修改_mount: /dev/vdb 写保护,将以只读方式挂载
  10. nodejs,express链式反应
  11. Node.js Net 模块
  12. 稳定币usda是哪个发行的_usdt稳定币是谁发行的?
  13. qt实现仓库物料管理(小工具)
  14. mysql 误删表 恢复数据_MySQL误删数据或者误清空表恢复
  15. 解决Iphonex 底部按钮fixed,bottom:0 底部留白问题
  16. GTK、GDK、GLIB三者的关系 - 阿堂的专栏 - 博客频道 - CSDN.NET
  17. 关于爆仓那些事,出现爆仓就是黑平台?
  18. Windows Mobile 6 SDK 中的 GPS 工具
  19. 三菱FX3U PLC模拟量输出FB (FX2N-4DA)
  20. 大道至简 知易行难 C# 完成WebSocket demo 用GoEasy实现Hello world

热门文章

  1. Qt之生成PDF(图片生成,文本生成)
  2. electron-vue 入门
  3. 国内GIS有哪些大niu?他们的研究方向分别是什么呢?
  4. html列表序号为圆点的,HTML列表
  5. python 一个通用的POC模板
  6. 有感于“学术官僚化、大学衙门化,教授奴才化”
  7. GLASS数据预处理/MRT工具批量处理MODIS数据
  8. 用于改进筛查的乳腺癌异常检测
  9. 高逼格的实现WiFi共享,不安装第三方wifi共享软件,两种方式实现开启wifi的功能
  10. access窗体中再制作查询窗体_2020(通用版)财务记账管理系统,可备份可查询可初始化,超实用...