1. 数据库(JDBC、DBMS)
1. JDBC:JNDI--DataSource---连接池(c3p0\dbcp\Proxool)----DriverManager---connection
oracle的数据库驱动:oracle.jdbc.driver.OracleDrive
mysql 的数据库驱动:com.mysql.jdbc.Driver
驱动的加载方法有:
a、调用方法class.forName
b、通过添加系统的jdbc.drive属性
c、通过registerDriver方法注册
----------------有待整理-----------------
JDBC-ODBC方式实现:
建立JDBC-ODBC桥接器,(使用java.lang中的class类,使用静态方法forName加载驱动)
创建ODBC数据源,
建立与ODBC的连接(可能异常)
----------------有待整理-----------------
2. 数据库连接方式有两种:
1.建立JDBC--ODBC桥接器(微软提供)依赖平台,
2.直连纯Java数据库驱动(数据库厂家提供例如 mysql的mysql-connector-java.jar)
3.数据库实现查询功能流程:
1. 加载JDBC驱动
2.建立并获取数据库连接----->通过连接池建立多个连接备用,使用什么连接池用户自定
3. 创建JDBC statements对象--
4.设置SQL语句的传入参数->用if,else判断传入的参数#变量名#占位符 $变量名$非占位符
5.执行SQL语句并获得查询结果
6.对结果进行转换处理并返回
7.释放相关资源
经过优化之后:
(1) 使用数据库连接池对连接进行管理
(2) SQL语句统一存放到配置文件中
(3) SQL语句变量和传入参数的映射以及动态SQL
(4) 动态SQL语句处理
(5) 对数据库操作结果的映射和结果缓存
(6) SQL语句的重复
4. PreparedStatement和Statement的区别:
1.创建时:
1) Statement statement = conn.creatStatement();
2) PrepareStatement preStatement = conn.PrepareStatement(sql);
2.执行时:
1) ResultSet rSet = statement.executeQuery(sql);
2) ResultSet pSet=preStatement.executeQuery();
PreStatement 有预编译过程,已经绑定sql,之后无论执行什么遍,都不会再去编译。
而statement不同,如果执行多遍,就需要编译多遍,所以prestatement效率比较高。
3)安全性:prepareStatement是预编译的,所以可以有效的防止SQL注入等问题。
4)可读和维护:后期维护prepareStatement也比较好读。
5. DBMS:数据库管理系统,事务具有持久性、一致性、原子性、隔离性。
持久性实现恢复管理子系统,一致性实现并发控制子系统,
原子性实现完整子系统,隔离性实现安全控制管理子系统。
一般关系数据模型和对象数据模型之间有以下对应关系:表对应类、记录对应对象、字段对应属性,ORMapping只是规定了结构和集的映射。
6. 数据库的优化:
1.索引:
项目中使用到的内容:
1. 外键约束:
CREATE TABLE review (
id int(11) NOT NULL AUTO_INCREMENT,
content varchar(4000) DEFAULT NULL,
uid int(11) DEFAULT NULL,
pid int(11) DEFAULT NULL,
createDate datetime DEFAULT NULL,
PRIMARY KEY (id),
CONSTRAINT fk_review_product FOREIGN KEY (pid) REFERENCES product (id),
CONSTRAINT fk_review_user FOREIGN KEY (uid) REFERENCES user (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
外键约束使用最多的两种情况:
1)父表更新时子表也更新,父表删除时如果子表有匹配的项,删除失败;
2)父表更新时子表也更新,父表删除时子表匹配的项也删除。
前一种情况,在外键定义中,我们使用ON UPDATE CASCADE ON DELETE RESTRICT;
后一种情况,可以使用ON UPDATE CASCADE ON DELETE CASCADE。
使用案例:
(1)创建表:
代码如下
CREATE TABLE IF NOT EXISTS `article` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`category_id` int(11) NOT NULL,
`name` char(16) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_1` (`category_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `article` (`id`, `category_id`, `name`) VALUES
(1, 1, '文章1');
CREATE TABLE IF NOT EXISTS `category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(16) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
INSERT INTO `category` (`id`, `name`) VALUES
(1, '分类1');
创建外键约束:
代码如下
ALTER TABLE `article`
ADD CONSTRAINT `fk_1` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`);
(2)删除主表category中数据:delete FROM `category` WHERE id=1,会报错:
#1451 - Cannot delete or update a parent row: a foreign key constraint fails (`test`.`article`, CONSTRAINT `fk_1` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`))
(3)从表article中,添加不存在的category_id:insert into article(category_id,name) values(2,'分类2') 会报错:
#1452 - Cannot add or update a child row: a foreign key constraint fails (`test`.`article`, CONSTRAINT `fk_1` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`))
(4)更改更新删除约束
代码如下
--删除外键
ALTER TABLE article DROP FOREIGN KEY fk_1
--添加外键
ALTER TABLE `article` ADD CONSTRAINT `fk_1` FOREIGN KEY ( `category_id` )
REFERENCES `category` ( `id` )
ON DELETE CASCADE ON UPDATE CASCADE
此时如下操作:
代码如下 复制代码
--此时article中的记录也会被删除
delete from category where id=1;
--此时article中的category_id也会被更新成3
UPDATE `test`.`category` SET `id` = '3' WHERE `category`.`id` =2;
2020-04-10:
Hibernate 使用 MySQL:
Hibernate 在执行 insert into 时,发现:
Caused by: com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (5,357 > 1,024). You can change this value on the server by setting the 'max_allowed_packet' variable.
这个问题 在 使用 jdbc 执行插入操作时没有出现过,怀疑是 hibernate 在执行 事务操作时,打包的数据量超过了 1024kb 造成的。
修改mysql 服务参数,并重启
查询 当前的 值: show VARIABLES like '%max_allowed_packet%';
设置 该值为 20M set global max_allowed_packet = 2*1024*1024*10;
2. 事务操作 MySQL 插入数据, id 自增问题
当 在一个事务中,执行了一次 插入操作,但是没有提交,然后关闭了连接, 在执行一次插入操作,就发现 自增的id 不是连续醒的。
因为在 MySQL 启动的时候,执行了 select max(*) from table ,获取了当前的最大id(注意,此处是id号,并不是行号), 并将该值保存在内存中,当第一次插入操作执行 auto_increment 时,auto_increment的计数器的值 + 1 ,但是没有提交就关闭了数据库连接,所以数据库没有该条数据。
再执行一次事务插入操作,并提交。使用 auto_increment的计数器的值 + 1 作为该记录的 id 值插入数据库。
为此,特意,在一次事务失败之后,重启数据库测试:
想象:执行一次事务 插入操作,不提交,此时 auto_increment 的 值 应该+1
重启 数据库,此时 auto_increment 获取数据库 表的 最大id值,
再执行一次完整的事务插入操作,并提交,此时 数据库的 id 应该是连续的。
关于 id自增 是不是 临时存入数据库 还是 保存到 日志文件中,有时间了看看MySQL的书籍。