Spring笔记(3):JdbcTemplate、事务管理、Spring5

目录

1、JdbcTemplate

1.1、方法:

1.2、举例:

2、事务管理

2.1、注解实现声明式事务管理:

(2)xml实现声明式事务管理:

3、Spring5新特性

3.1. 自带了日志封装

3.2. @Nullable注解

3.3. 支持函数式风格编程

3.4. 支持整合JUnit5


1、JdbcTemplate

  • Spring对JDBC进行封装,使用JdbcTemplate方便对数据库的操作。
    • 引入依赖
    • 在spring配置文件配置数据库连接池
    • 配置jdbcTemplate对象,注入DataSource
    • 创建service类,创建dao类,在dao注入jdbcTemplate对象

1.1、方法:

(1)增删改操作:

int update(String sql, Object... args);

(2)查询:返回某个值

T queryForObject(String sql,Class requiredType);

(3)查询:返回某个对象

T queryForObject(String sql,RowMapper rowMapper,Object ... args);

(4)查询:返回集合

List query(String sql,RowMapper rowMapper,Object... args);

(5)批量增删改:

int[] batchUpdate(String sql,List batchArgs);

1.2、举例:

  • 引入相关jar包
 
            org.springframework
            spring-webmvc
            5.1.8.RELEASE
        
  • 配置数据库连接池;配置JdbcTemplate对象




    
    
    
    




    
    

  • 创建Service类和Dao类,在Dao类中注入JdbcTemplate对象
public interface BookDao {

    public void add(Book book);  //添加图书

    public void update(Book book);  //修改图书

    public void delete(int id);  //删除图书

    public int queryCount();   //查询数量

    public Book queryBookById(int id);  //查询某本书

    public List queryBooks();   //查询所有书

    public void batchAddBook(List books);  //批量添加图书

    public void batchUpdateBook(List books);  //批量修改图书

    public void batchDeleteBook(List args);  //批量删除图书
}

@Repository
public class BookDaoImpl implements BookDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void add(Book book) {
        String sql = "insert into t_book set name=?,price=?";
        Object[] args = {book.getBookName(),book.getBookPrice()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void update(Book book) {
        String sql = "update t_book set name=?,price=? where id=?";
        Object[] args = {book.getBookName(),book.getBookPrice(),book.getBookId()};
        int update = jdbcTemplate.update(sql, args);
        System.out.println(update);
    }

    @Override
    public void delete(int id) {
        String sql = "delete from t_book where id=?";
        int update = jdbcTemplate.update(sql, id);
        System.out.println(update);
    }

    @Override
    public int queryCount() {
        String sql = "select count(*) from t_book";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
        return count;
    }

    @Override
    public Book queryBookById(int id) {
        String sql = "select id bookId,name bookName,price bookPrice from t_book where id=?";
        Book book = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper(Book.class), id);
        return book;
    }

    @Override
    public List queryBooks() {
        String sql = "select id bookId,name bookName,price bookPrice from t_book";
        List bookList = jdbcTemplate.query(sql, new BeanPropertyRowMapper(Book.class));
        return bookList;
    }

    @Override
    public void batchAddBook(List books) {
        String sql = "insert into t_book set id=?,name=?,price=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, books);
        System.out.println(ints);
    }

    @Override
    public void batchUpdateBook(List books) {
        String sql = "update t_book set name=?,price=? where id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, books);
        System.out.println(ints);
    }

    @Override
    public void batchDeleteBook(List args) {
        String sql = "delete from t_book where id=?";
        int[] ints = jdbcTemplate.batchUpdate(sql, args);
        System.out.println(ints);
    }
}

@Service
public class BookService {
    @Autowired
    private BookDao bookDao = new BookDaoImpl();
    //添加图书
    public void add(Book book){
        bookDao.add(book);
    }
    //修改图书
    public void update(Book book){
        bookDao.update(book);
    }
    //删除图书
    public void delete(Integer id){
        bookDao.delete(id);
    }
    //查询数量
    public int queryCount(){
        return bookDao.queryCount();
    }
    //查询图书
    public Book queryBookById(Integer id){
        return bookDao.queryBookById(id);
    }
    //查询所有图书
    public List queryBooks(){
        return bookDao.queryBooks();
    }
    //批量添加图书
    public void batchAddBook(List books){
        bookDao.batchAddBook(books);
    }
    //批量修改图书
    public void batchUpdateBook(List books){
        bookDao.batchUpdateBook(books);
    }
    //批量删除图书
    public void batchDeleteBook(List args){
        bookDao.batchDeleteBook(args);
    }
}

2、事务管理

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第1张图片

 事务是数据库操作最基本单位,要么都成功,要么都失败。

  • 典型场景:转账
  • 事务四个特性ACID:
    • 原子性
    • 一致性
    • 隔离性
    • 持久性
  • Spring事务管理有两种方式:
    • 编程式事务管理
    • 声明式事务管理
    • 一般使用声明式事务管理,底层使用AOP原理。
  • 声明式事务管理有两种方式:基于xml配置方式 和 基于注解方式,一般使用注解方式
  • Spring事务管理提供了一个接口,叫事务管理器,该接口针对不同的框架提供不同的实现类。

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第2张图片

        对于使用JdbcTemplate进行数据库交互,则使用DataSourceTransactionManager实现类,如果整合Hibernate框架则使用HibernateTransactionManager实现类,具体情况具体使用。

案例分析:

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第3张图片

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第4张图片

public interface UserDao {

    //多钱
    public void addMoney();
    //少钱
    public void reduceMoney();
}
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    @Override
    public void addMoney() {
        String sql = "update user_db set money = money + ? where username = ?";
        jdbcTemplate.update(sql,100,"mary");
    }

    @Override
    public void reduceMoney() {
        String sql = "update user_db set money = money - ? where username = ?";
        jdbcTemplate.update(sql,100,"lucy");
    }
}
@Service
public class UserService {

    //注入dao
    @Autowired
    private UserDao userDao;

    //转账
    public void accountMoney(){
        //lucy少100
        userDao.reduceMoney();
        //mary多100
        userDao.addMoney();

    }
}




   

   
   
      
      
      
      
   

   
   
      
      
   



public class TestBook {

    @Test
    public void testAccount(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.accountMoney();

    }
}

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第5张图片

上述代码,如果正常执行没有问题,但是如果代码执行过程中,出现异常会有问题。

问题例如:

@Service
public class UserService {

    //注入dao
    @Autowired
    private UserDao userDao;

    //转账
    public void accountMoney(){
        //lucy少100
        userDao.reduceMoney();

        //模拟异常
        int i = 100/0;

        //mary多100
        userDao.addMoney();

    }
}

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第6张图片

如何解决:

使用事务,事务过程:

@Service
public class UserService {

    //注入dao
    @Autowired
    private UserDao userDao;

    //转账
    public void accountMoney(){
        try {
            //1、开启事务

            //2、处理逻辑
            //lucy少100
            userDao.reduceMoney();

            //模拟异常
            int i = 100/0;

            //mary多100
            userDao.addMoney();

            //3、没有异常,提交事务
        } catch (Exception e) {
            //4、出现异常,事务回滚
        }

    }
}

1、事务添加到三层结果里Service层(业务逻辑层)

2、在Spring进行事务管理操作

  • 有两种方式:编程式事务管理和声明式事务管理(使用)

3、编程式事务管理:上面代码的1234步骤

4、声明式事务管理有两种方式:基于xml配置方式 和 基于注解方式,一般使用注解方式

5、在Spring进行声明式事务管理,底层使用AOP原理

6、Spring事务管理API

  • 提供了一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类。

 对于使用JdbcTemplate进行数据库交互,则使用DataSourceTransactionManager实现类,如果整合Hibernate框架则使用HibernateTransactionManager实现类,具体情况具体使用。

2.1、注解实现声明式事务管理:

  • 在spring配置文件,配置事务管理器
  • 在spring配置文件,开启事务注解
  • 在service类上面或者service类的方法上面添加事务注解@Transactional




    
    
    
    




    
    




    




在service类上面或者service类的方法上面添加事务注解@Transactional

  • 如果把@Transactional添加在类上面,这个类里面所有方法都添加事务。
  • 如果只是添加在方法上面,则只为这个方法添加事务。

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第7张图片

声明式事务管理的参数配置:

在service中配置@Transactional注解,在这个注解里可以配置事务参数:

  1. propagation:事务传播行为,总共有7种

事务方法:对数据库表数据进行变化的操作,比如更新,增加,删除。查询不是。

多事务方法直接进行调用,这个过程中事务是如何进行管理的。例如:

  •  一个事务方法调用另一个无事务方法
  •  一个无事务方法调用另一个事务方法
  •  一个事务方法调用另一个事务方法

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第8张图片required:如果add方法本身有事务,调用update方法之后,update使用当前add方法里面事务,如果add方法本身没有事务,调用update方法之后,创建新事物

required_new:使用add方法调用update方法,如果add 无论是否有事务,都创建新的事务。

@Service
@Transactional(propagation = Propagation.REQUIRED)
public class UserService {

}
  1. isolation:事务隔离级别

    不考虑隔离型会有三个读问题:脏读,不可重复读,虚读(幻读)。

    设置隔离级别,解决读问题:

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第9张图片

@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {

}

    3. timeout:超时时间

  • 事务需要在一定时间内进行提交,超过时间后回滚。
  • 默认值是-1,表示不超时,设置时间以秒为单位。
@Service
@Transactional(timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {

}

    4. readOnly:是否只读

  • 默认值为false,表示可以查询,也可以增删改。
  • 设置为true,只能查询。
@Service
@Transactional(readOnly = true,timeout = -1,propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
public class UserService {

}

    5. rollbackFor:回滚,设置出现哪些异常进行事务回滚。
    6. noRollbackFor:不回滚,设置出现哪些异常不进行事务回滚。

@Service
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_COMMITTED)
public class AccountService {

}

完全注解实现声明式事务管理:

创建配置类,使用配置类代替xml配置文件

@Configuration  //配置类
@ComponentScan(basePackages = "com.oymn.spring5")  //开启组件扫描
@EnableTransactionManagement  //开启事务
public class Config {

    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("123456");
        return druidDataSource;
    }
    //创建JdbcTemplate对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        //到ioc容器中根据类型找到dataSource        
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }
}
@Service
public class AccountService {

    @Autowired
    private AccountDao accountDao;

    @Transactional
    public void accountMoney(){
        accountDao.add();
        //int i=1/0;   //用来模拟转账失败
        accountDao.reduce();
    }
}

(2)xml实现声明式事务管理:

  • spring配置文件中配置事务管理器
  • spring配置文件中配置通知
  • spring配置文件中配置切入点和切面




    
    
    
    




    
    




    




    
    
        
    




    
    
    
    

3、Spring5新特性

  • 整个Spring5框架的代码基于Java8,运行时兼容JDK9,许多不建议使用的类和方法在代码库中删除。
  • Spring5.0框架 自带了通用的日志框架

3.1. 自带了日志封装

  • Spring5移除了Log4jConfigListener,官方建议使用Log4j2

Spring5整合Log4j2:

第一步:引入jar包


		
            org.apache.logging.log4j
            log4j-api
            ${log4j.version}
        

        
            org.apache.logging.log4j
            log4j-core
            ${log4j.version}
        

        
            org.apache.logging.log4j
            log4j-web
            ${log4j.version}
        

第二步:创建log4j2.xml配置文件





    
    
        
        
            
            
        
    
    
    
    
        
            
        
    

public class UserLog {

    private static final Logger log = LoggerFactory.getLogger(UserLog.class);

    public static void main(String[] args) {
        log.info("hello log4j2");
        log.warn("hello log4j2");
    }
}

02:33:32.740 [main] INFO springtransaction.UserLog - hello log4j2
02:33:32.747 [main] WARN springtransaction.UserLog - hello log4j2

3.2. @Nullable注解

  • @Nullable注解可以用在方法上,属性上,参数上,表示方法返回值可以为空,属性可以为空,参数可以为空。

@Nullable     //表示方法返回值可以为空
public int getId();

@Nullable     //表示参数可以为空
public void setId(@Nullable int Id);

@Nullable     //表示属性可以为空
public int id;

3.3. 支持函数式风格编程

这是因为java8新增了lamda表达式

@Test
public void test() {
    //1 创建 GenericApplicationContext 对象
        GenericApplicationContext context = new GenericApplicationContext();
        //2 调用 context 的方法对象注册
        context.refresh();
        context.registerBean("user1", User.class,() -> new User());
        //3 获取在 spring 注册的对象
        User user = (User)context.getBean("user1");
        System.out.println(user);//aopanno.User@3d0f8e03

        //3 获取在 spring 注册的对象
        //使用全路径
        context.registerBean( User.class,() -> new User());
        User user1 = (User)context.getBean("com.atguigu.spring5.test.User");
        System.out.println(user1);//aopanno.User@3d0f8e03
    
}

3.4. 支持整合JUnit5

(1)整合JUnit4:

第一步:引入jar包


            org.springframework
            spring-test
            5.2.8.RELEASE
        

    junit
    junit
    4.12
    test

第二步:创建测试类,使用注解方式完成

@RunWith(SpringJUnit4ClassRunner.class) //单元测试框架版本
@ContextConfiguration("classpath:bean4.xml") //加载配置文件
public class JUnitTest {

    @Autowired
    public User user;

    @Test
    public void test(){
        System.out.println(user);
    }
}

其中

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:bean1.xml")
相当于
ApplicationContext context=new AnnotationConfigApplicationContext(Config.class);

bean4.xml:


通过使用@ContextConfiguration注解,测试方法中就不用每次都通过context来获取对象了,比较方便。

ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
BookService bookService = context.getBean("bookService",BookService.class);

(2)整合JUnit5:


     org.junit.jupiter
      junit-jupiter
      5.6.2
      test

Spring笔记(3):JdbcTemplate、事务管理、Spring5_第10张图片


 

你可能感兴趣的:(java)