1、Spring JDBC
2、Mysql事务
3、Mysql触发器
(1)使用Hikaricp连接池进行数据库连接,需要的jar包
mysql-connector-java.jar
HikariCP.jar
spring-jdbc.jar
(2)配置数据源文件db.properties,url需要设置时区,否则可能会报错
配置驱动Driver时,如果mysql-connector-java.jar版本在6以上,则是com.mysql.cj.jdbc.Driver,否则是com.mysql.jdbc.Driver
db.driver=com.mysql.cj.jdbc.Driver db.userName=root db.password=root db.url=jdbc:mysql:///book_db?characterEncoding=utf8&serverTimezone=UTC
(3)在applicationContext.xml文件中,获取配置文件并配置数据源。使用spring-jdbc.jar提供的JdbcTemplate类进行对数据库的操作,将数据源注入JdbcTemplate类中,这个类就相当于之前学习的DBHelp类,里面提供了对数据库进行操作的方法。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--开启基于注解的bean管理 依赖注入--> <context:component-scan base-package="com.hisoft"/> <!--获取配置文件--> <context:property-placeholder location="db.properties"/> <!--配置数据源--> <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="username" value="${db.userName}"/> <property name="password" value="${db.password}"/> <property name="jdbcUrl" value="${db.url}"/> <!--driver可以不用配置,导入mysql-connector-java.jar后会自动加载--> <property name="driverClassName" value="${db.driver}"/> </bean> <!--构建spring JdbcTemplate--> <bean id = "jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> </beans>
(4)BookDaoImpl类通过注解放入spring容器,并将jdbcTemplate对象自动注入
@Repository //Dao层使用@Repository注解注册bean public class BookDaoImpl implements BookDao { @Autowired //自动注入jdbcTemplate对象 private JdbcTemplate jdbcTemplate; @Override public void save(Book book) { String sql = "insert into book(bookname,author,publisher) values(?,?,?)"; jdbcTemplate.update(sql, book.getBookName(), book.getAuthor(), book.getPublisher()); } public List<Book> findAll(){ String sql = "select id,bookname,author,publisher from book"; return jdbcTemplate.query(sql,new BookRowMapper()); } @Override public Long getCount() { String sql = "select count(*) from book"; //使用局部匿名内部类 return jdbcTemplate.queryForObject(sql, new RowMapper<Long>() { @Override public Long mapRow(ResultSet rs, int i) throws SQLException { return rs.getLong(1); } }); } public Book findById(int id) { String sql = "select id,bookname,author,publisher from book where id = ?"; //return jdbcTemplate.queryForObject(sql, new BookRowMapper(),id); List<Book> bookList = jdbcTemplate.query(sql,new BookRowMapper(),id); if(bookList.size() > 0){ return bookList.get(0); } return null; } //可以写一个内部类实现spring的RowMapper<> private class BookRowMapper implements RowMapper<Book> { @Override public Book mapRow(ResultSet rs, int row) throws SQLException { Book book = new Book(); book.setId(rs.getInt("id")); book.setBookName(rs.getString("bookname")); book.setAuthor(rs.getString("author")); book.setPublisher(rs.getString("publisher")); return book; } } }
(5)BookServiceImpl类通过注解放入spring容器,并将BookDao对象自动注入
@Service("bookService") public class BookServiceImpl { @Autowired private BookDao bookDao; public void save(Book book){ bookDao.save(book); } public Book findById(int id){ return bookDao.findById(id); } public List<Book> findAll(){ return bookDao.findAll(); } public Long getCount(){ return bookDao.getCount(); } }
(6)测试
public class BookServiceTest { public static void main(String[] args) { AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); BookServiceImpl bookService = (BookServiceImpl) context.getBean("bookService"); System.out.println(bookService.getCount()); Book book = bookService.findById(101); System.out.println(book.toString()); List<Book> all = bookService.findAll(); System.out.println(all.size()); Book book = new Book(); book.setBookName("红楼梦"); book.setPublisher("北京出版社"); book.setAuthor("曹雪芹"); bookService.save(book); } }
(1)事务的四个特征(ACID属性)
原子性(Atomic):组成事务的处理语句组成了一个逻辑单元,这是最小的执行单位。
一致性(Consistent):在事务处理执行之前和之后,数据是一致的。
隔离性(Isolated):一个事务的处理对另一个事务没有影响。
持续性(Durable):当事务处理成功后,其结果在数据库中被永久记录下来。
(2)在MySQL中只有使用了Innodb数据库引擎的数据库或表才支持事务,事务用来管理insert、update、delete语句,可以用来维护数据库的完整性,保证成批的SQL操作要么完全执行,要么完全不执行,事务处理的关键在于将SQL语句组分解为逻辑块,并明确规定数据何时应归回滚,何时提交。
(3)事务的术语
事务(transaction):指一组SQL语句
回滚(rollback):指撤销指定SQL语句的过程
提交(commit):指将未存储的SQL语句结果写入到数据库中
保留点(savepoint):指事务处理中设置的临时占位符,可以对它进行回滚
(4)使用事务
开始事务:START TRANSACTION
回滚事务:ROLLBACK
/*事务演示*/ SELECT * FROM t_table; START TRANSACTION;/*开始事务*/ DELETE FROM t_tableA WHERE id = 1; ROLLBACK;/*事务回滚,删除没有成功*/ SELECT * FROM t_table;
提交事务:COMMIT
/*事务演示:提交*/ START TRANSACTION; DELETE FROM t_tableA WHERE id = 1; COMMIT; /*事务提交,删除成功*/ SELECT * FROM t_tableA;
使用保留点:
SAVEPOINT s1
ROLLBACK TO s1
START TRANSACTION; DELETE FROM t_tableA WHERE id = 4; SAVEPOINT s1; /*声明一个保留点*/ DELETE FROM t_tableA WHERE id = 5; ROLLBACK TO s1; /*回滚到s1保留点*/
(1)触发器是MySQL响应insert、update、delete语句时自动执行的一条SQL语句,只有表支持触发器,视图不支持。
(2)触发器需要的信息
1.唯一的触发器名称(一个表中触发器名称唯一,而不是在一个数据库中唯一)
2.触发器关联的表
3.触发器应该响应的事件(insert?update?delete?)
4.触发器何时执行(处理之前或之后)
5.一个表的一个事件最多只能有两个触发器(处理之前和处理之后),所以一个表最多有6个触发器
6.如果响应之前的触发器执行失败,响应则不会执行;响应之前的触发器或响应执行失败,那么响应之后的触发器则不会执行
(3)inset触发器
/*触发器*/ CREATE TABLE t_tableA( /*两个测试表*/ id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, val VARCHAR(20) ); CREATE TABLE t_tableB( id INT PRIMARY KEY NOT NULL AUTO_INCREMENT, val VARCHAR(20) ); /*创建insert后置触发器*/ DELIMITER // CREATE TRIGGER tr_insert_tableA /* tr_insert_tableA为触发器的名字*/ AFTER INSERT ON t_tableA /*一个后置的(AFTER)insert(INSERT )在t_tableA表上的触发器*/ FOR EACH ROW /*对所有代码行都执行*/ INSERT INTO t_tableB(val) VALUES(new.val); END// DELIMITER /*触发器内容,将a表中插入的数据放到b表中一份,insert触发器会访问一个名称为new的虚拟表,获取刚插入的值*/ /*测试触发器*/ INSERT INTO t_tableA(val) VALUES('abc') SELECT * FROM t_tableA; SELECT * FROM t_tableB;
1.在Insert触发器内,可引用一个名为NEW的虚拟表,访问被插入的行
2.在before insert触发器中,NEW中的值也可以被更新(运行更改被插入的值)
3.对于自动增长列,NEW在insert执行之前的值为0,在执行之后是新的自动生成的值
/*第二个触发器:获取刚刚插入的自动生成的主键值*/ CREATE TRIGGER t_insert_pk_tableA AFTER INSERT ON t_tableA FOR EACH ROW SELECT new.id INTO @id; /*测试触发器*/ INSERT INTO t_tableA(val) VALUES('abc'); SELECT @id;
(4)delete触发器
1.在DELETE触发器代码中,可以引用一个OLD的虚拟表,访问被删除的行
2.OLD表中的值全部是只读的,不能更新
DELIMITER // CREATE TRIGGER t_delete_tableA AFTER DELETE ON t_tableA /*DELETE后置触发器*/ FOR EACH ROW BEGIN INSERT INTO t_tableB (val) VALUES(old.val); END// DELIMITER; /*测试触发器*/ DELETE FROM t_tableA WHERE id = 2
(5)update触发器
/*将a表中修改后的名字都改为大写*/ DELIMITER // CREATE TRIGGER t_update_tableA BEFORE UPDATE ON t_tableA FOR EACH ROW BEGIN SET new.val = UPPER(new.val); END// DELIMITER; /*测试触发器*/ UPDATE t_tableA SET val = 'xyz' WHERE id = 1; SELECT * FROM t_tableA;
1.在UPDATE触发器代码中,可以引用一个名为OLD的虚拟表访问以前的值,引用一个名为NEW的表访问新更新的值
2.在befor update触发器中,new表中的值允许被更新(允许更改将要用于update语句中的值)
3.OLD表中的值都是只读的,不能更行
(6)删除一个触发器
DROP TRIGGER tr_insert_tableA