天天看点

学习日志day50(2021-09-16)(1、Spring JDBC 2、Mysql事务 3、Mysql触发器)学习内容:学习Spring框架(Day50)

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

1、Spring JDBC

2、Mysql事务

3、Mysql触发器

4、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.一个表的一个事件(insert update delete)最多只能有两个触发器(处理之前和处理之后),所以一个表最多有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

4、Mysql视图

(1)视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询,而自身不包含任何数据。视图的作用如下:

1.重用SQL语句

2.简化复杂的SQL操作

3.使用表的组成部分而不是整个表

4.保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限

5.更改数据格式和表示

(2)视图的规则与限制

1.与表一样,视图必须唯一命名

2.在一个数据库中,可以创建的视图数目没有限制

3.视图可以嵌套,即可以利用从其他视图中查询出来的数据构建新的视图

4.order by可以用在视图中,但如果从该视图检索数据的select中也含有order by,那么该视图中的Order by将会被覆盖

5.视图不能索引,也不能有关联的触发器或默认值

6.视图和表可以一起使用,例如编写一条联接表和视图的查询

(3)视图使用CREATE VIEW语句创建

CREATE VIEW v_customers AS

SELECT customers.cust_name,customers.cust_id,COUNT(orders.order_num)

FROM customers LEFT OUTER JOIN orders

ON customers.cust_id = orders.cust_id

GROUP BY customers.cust_id

(4)查询视图:select * from v_customers

CREATE VIEW v_vendors AS

SELECT CONCAT(vend_name,’(’,vend_city,’)’) AS ‘name and city’ FROM vendors

CREATE VIEW v_orderitemsprice AS

SELECT order_num,item_price,quantity,quantity * item_price AS ‘total’ FROM orderitems

(5)使用SHOW CREATE VIEW viewname来查看创建视图的语句

(6)用DROP删除视图,语法为DROP VIEW viewname

(7)视图的更新

对视图进行insert update delete将会影响其基表,因为视图中不包含任何数据,不是迫不得已,不要对视图进行更新操作,因为效率低。视图主要用于查询。

不是所有视图都可以更新:

1.含有分组(group by 和 having)

2.联接查询

3.子查询

4.聚合函数

5.DISTINCT