学习日志day50(2021-09-16)(1、Spring JDBC 2、Mysql事务 3、Mysql触发器)

学习内容:学习Spring框架(Day50)

1、Spring JDBC
2、Mysql事务
3、Mysql触发器


1、Spring JDBC

(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);
    }
}

2、Mysql事务

(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保留点*/

3、Mysql触发器

(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

上一篇:「小程序JAVA实战」小程序的横向视频和页面拦截(59)


下一篇:「小程序JAVA实战」小程序的页面重定向(60)