一、重点知识
cmment数据库中创建表加注释
工作中最好手写sql语句,方便后人查看
描述数据库的实体类中一定要用包装类
因为判断用Null,而基本数据类型默认值为0,但是如果给int赋值时赋值的就是0,那么不利于判断,且如果成员变量的值还未确定,用Integer的话,只须令这个成员为NULL; 但如果用int的话,就必然存在问题,因为一个int成员变量的值总是确定的,即使你没给它赋任何值,它的值就是0
@before注解用在单元测试中,表示任何一个单元测试在运行之前都会先执行brfore后面的方法
@after注解用在单元测试中,表示任何一个单元测试在运行之后都会先执行after后面的方法
在jdbc中写数据库语句关键字一定要大写,因为数据库会优先编译大写的,这样会提高编译效率
写代码注意内存分析
json格式化,可以格式化java查询结果
在与数据库建立连接时候可以规定字符集
获取新插入数据主键的方式
statement .getGeneratedKeys();返回一个set集合,自能返回自增的主键,一个表只能有一个自增的主键,所以实际上他只返回了一个值
如果想要获取主键要在statement.excuteupdata中多加一个参数
Statement.RETURN_GENERATED_KEYS,这样才可以获取到主键
工作时一定要加事务
二、重点问题
数据库的事务特性
1、原子性:把一组事务看为一个最小的单位,不可分割
2、一致性 : 数据库操作前后的总量不变
3、 隔离性 : 同一时间只允许一个操作数据
4、永久性 : 不commit()就不提交数据 ,commit()数据后就会永久存储
数据库的隔离级别
事务的四大特性分别是:原子性、一致性、隔离性、持久性
幻读和不可重复读都是在同一个事务中多次读取了其他事务已经提交的事务的数据导致每次读取的数据不一致,所不同的是不可重复读读取的是同一条数据,而幻读针对的是一批数据整体的统计(比如数据的个数)
以MYSQL数据库来分析四种隔离级别
第一种隔离级别:Read uncommitted(读未提交)
如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据
解决了更新丢失,但还是可能会出现脏读
第二种隔离级别:Read committed(读提交)
如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
解决了更新丢失和脏读问题
第三种隔离级别:Repeatable read(可重复读取)
可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现。
解决了更新丢失、脏读、不可重复读、但是还会出现幻读
第四种隔离级别:Serializable(可序化)
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读
解决了更新丢失、脏读、不可重复读、幻读(虚读)
课堂知识
一,JDBC
1.1 概念
概念:Java DataBase Connectivity ,Java 数据库连接,JDBC让我们可以通过Java操作数据库
JDBC本质:它是官方推出的一套专门用于操作关系型数据库的规则,就是接口。各个不用的数据库厂商都去实现这个接口,并提供相应的jar包。我们可以使用这些jar包针对不同的关系型数据库进行数据库的操作。
1.2 使用步骤
导入jar包(数据库驱动包)mysql-connector-java-5.1.37-bin.jar
导入步骤:
在项目的根目录下创建 libs 文件夹
将驱动包复制到 libs 下
右键选中此 jar 文件,点击 Build Path ,再点击 Add to Build Path
注:如果导入 jar包报错,需要删除,删除的步骤是
右键项目,选中 Build Path,选择 Configure Build Path
找到 libraries 标签页,选择指定的资源点击 remove
注册驱动
获取数据库连接对象
定义SQL语句
获取执行SQL语句的对象
执行
接收返回的结果
处理结果
释放资源
1.3 常见错误
- ClassNotFoundException:找不到类,一般是驱动包的类名问题
- Unknown database 'xxx':找不到数据库,一般是数据库库名的问题
- Access denied for user 'xxx'@'localhost' (using password: YES):访问数据库被拒绝,一般是数据库的用户名或者密码有误
- SQLException:数据库异常
- MySQLSyntaxErrorException:数据库语法错误
1.4 细节问题
注册驱动:告知程序要使用哪一个数据库的jar包
Class.forName("com.mysql.jdbc.Driver");
注:mysql5版本以后,注册驱动的语句可以省略
Connection连接对象
/* * 参数: * 1.要连接的数据库: jdbc:mysql://地址:端口号/库名 ; 如果地址是本机,端口是3306,那么可以写成:jdbc:mysql:///库名 * 2.数据库管理员身份的用户名 * 3.数据库管理员身份的密码 */ Connection conn = DriverManager.getConnection("jdbc:mysql:///0519pm", "root", "1234");
Statement执行对象
- 用于执行SQL语句
- executeUpdate(String sql):执行增删改查,返回 int 值,表示影响的记录数
- executeQuery(String sql):执行查询,返回结果集 ResultSet
ResultSet结果集对象
- 用于封装查询后的结果
- 方法:
- next():判断是否有下一条可遍历的记录,返回布尔值
- getXxx(参数):该方法有重载,参数可以是int,也可以是String;参数是int时字段值根据字段在结果集中的第几列获取;参数是String时字段值根据字段名获取。
ResultSet、Statement、Connection都需要释放 close()
形参与SQL语句中的关键字之间要有空格,否则关键字与参数拼接会报错
1.5 SQL注入问题
用一些关键字与字符串进行拼接,会造成造成安全性的问题
例如:select * from user where username = 'qwer' and password = '1234' or '1' = '1'; '1' = '1' 是一个恒等式结果永远为true,而 '1' = '1'前又使用了or关键字,从而导致了用户名和密码有误也能成功登录。
解决办法:使用PreparedStatement对象
参数参与SQL语句不再使用字符串的拼接,而使用了占位符
占位符中的关键字,不再以关键字的形态出现
1.5.1 PreparedStatement的获取
PreparedStatement pstmt = conn.preparedStatement(String sql);
将SQL语句预编译
1.5.2 PreparedStatement的功能
- 为占位符设置值
- setXxx(参数1,参数2)
- 参数1:问号的位置,从1开始
- 参数2:问号位置上的值
- 执行SQL
- executeUpdate():执行增删改查,返回 int 值,表示影响的记录数
- executeQuery():执行查询,返回结果集 ResultSet