零基础学习SpringBoot(二)--集成MyBatis以及开启事务

1. SpringBoot集成MyBatis

1.1 准备数据库

  • 启动数据库,并通过Navicat连接


    image
  • 创建新的数据库springboot,指定数据库字符编码为utf-8, 并创建表t_person

image
  • 向表中插入几条数据
image

1.2 创建新项目

image

1.3 在pom.xml中添加相关jar依赖

<!--MyBatis 整合SpringBoot的起步依赖-->
 <dependency>
     <groupId>org.mybatis.spring.boot</groupId>
     <artifactId>mybatis-spring-boot-starter</artifactId>
     <version>2.1.3</version>
 </dependency>

 <!--MySql 的驱动依赖-->
 <dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
 </dependency>

1.4 在SpringBoot的核心配置文件application.properties中配置数据源

根据自己数据库的信息修改以下内容

server:
   # 配置内嵌Tomcat端口号
   port: 8888
   servlet:
   # 配置项目上下文根
     context-path: /springboot-web

# 配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2B8
    username: root
    password: 12345678

1.5 代码实现

1.5.1 使用Mybatis反向工程生成接口、映射文件以及实体Bean
  • 创建Mybatis反向工程配置文件 GeneratorMapper.xml

  • 在pom.xml文件中添加反向工程依赖

<!--Mybatis 代码动生成插件-->
 <plugin>
   <groupId>org.mybatis.generator</groupId>
   <artifactId>mybatis-generator-maven-plugin</artifactId>
   <version>1.3.6</version>
   <configuration>
     <!--配置文件的位置-->
     <configurationFile>GeneratorMapper.xml</configurationFile>
     <verbose>true</verbose>
     <overwrite>true</overwrite>
   </configuration>
 </plugin>
  • 修改GeneratorMapper.xml配置
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE generatorConfiguration
 PUBLIC  "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

   <!--指定连接数据库的JDBC驱动包所在位置, 指定到你本地的完整路径-->
   <classPathEntry location="/Volumes/developer/workspace/java-workspace/springboot/springboot-web/mysql-connector-java-8.0.25.jar"/>
   <!-- 配置 table 表信息内容体,targetRuntime 指定采用 MyBatis3 的版本 -->
   <context id="tables" targetRuntime="MyBatis3">
   <!-- 抑制生成注释,由于生成的注释都是英文的,可以不让它生成 -->
   <commentGenerator>
     <property name="suppressAllComments" value="true" />
   </commentGenerator>

   <!-- 配置数据库连接信息 -->
   <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
     connectionURL="jdbc:mysql://localhost:3306/springboot?useUnicode=true&amp;characterEncoding=UTF-8&amp;useJDBCCompliantTimezoneShift=true&amp;useLegacyDatetimeCode=false&amp;serverTimezone=GMT%2B8&amp;nullCatalogMeansCurrent=true"
     userId="root"
     password="12345678">
   </jdbcConnection>
   <!-- 生成 model 类,targetPackage 指定 model 类的包名, targetProject 指定生成的 model 放在 哪个工程下面-->
   <javaModelGenerator targetPackage="com.mufeng.springbootweb.model"
 targetProject="src/main/java">
     <property name="enableSubPackages" value="false" />
     <property name="trimStrings" value="false" />
   </javaModelGenerator>

   <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的包名, targetProject 指定生成的 mapper.xml 放在哪个工程下面 -->
   <sqlMapGenerator targetPackage="com.mufeng.springbootweb.mapper"
     targetProject="src/main/java">
     <property name="enableSubPackages" value="false" />
   </sqlMapGenerator>

   <!-- 生成 MyBatis 的 Mapper 接口类文件,targetPackage 指定 Mapper 接口类的包名, targetProject 指定生成的 Mapper 接口放在哪个工程下面 -->
   <javaClientGenerator type="XMLMAPPER"
     targetPackage="com.mufeng.springbootweb.mapper" targetProject="src/main/java">
     <property name="enableSubPackages" value="false" />
   </javaClientGenerator>

   <!-- 数据库表名及对应的 Java 模型类名 -->
   <table tableName="t_person" domainObjectName="Person"
     enableCountByExample="false"
     enableUpdateByExample="false"
     enableDeleteByExample="false"
     enableSelectByExample="false"
     selectByExampleQueryId="false"/>
   </context>

</generatorConfiguration>
  • 运行插件,生成相关文件
image
image
1.5.2 在controller包下创建PersonController并编写代码
package com.mufeng.springbootweb.controller;

import com.mufeng.springbootweb.model.Person;
import com.mufeng.springbootweb.services.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class PersonController {

   @Autowired
   private PersonService personService;

   @RequestMapping(value = "/springboot/getPersonDetails")
   @ResponseBody
   public Object getPersonDetails(){
     Person person = personService.findPersonById(1);
     return person;
   }

}
1.5.3 在Service包下创建service接口并编写代码
package com.mufeng.springbootweb.services;

import com.mufeng.springbootweb.model.Person;

public interface PersonService {

   /**
   * 根据用户标识获取用户详情
   * @param id
   * @return
   */
   Person findPersonById(Integer id);

}
1.5.4 在 service.impl 包下创建 service 接口并编写代码
package com.mufeng.springbootweb.services.impl;

import com.mufeng.springbootweb.mapper.PersonMapper;
import com.mufeng.springbootweb.model.Person;
import com.mufeng.springbootweb.services.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonServiceImpl implements PersonService {

   @Autowired
   private PersonMapper personMapper;

   @Override
   public Person findPersonById(Integer id) {
     return personMapper.selectByPrimaryKey(id);
   }
}
1.5.5 在 Mybatis 反向工程生成的 StudentMapper 接口上加一个 Mapper 注解

@Mapper 作用:mybatis 自动扫描数据持久层的映射文件及 DAO 接口的关系

package com.mufeng.springbootweb.mapper;

import com.mufeng.springbootweb.model.Person;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface PersonMapper {
   int deleteByPrimaryKey(Integer id);

   int insert(Person record);

   int insertSelective(Person record);

   Person selectByPrimaryKey(Integer id);

   int updateByPrimaryKeySelective(Person record);

   int updateByPrimaryKey(Person record);
}

注意:默认情况下,MyBatis的xml映射文件不会编译到target的class目录下,所以我们需要在pom.xml中配置resource

    <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>
                        **/*.xml
                    </include>
                </includes>
            </resource>
        </resources>

1.6 启动Application应用,访问测试

image

1.7 在运行的主类上添加mapper扫描注解

注释掉PersonMapper接口上的@Mapper注解

package com.mufeng.springbootweb.mapper;

import com.mufeng.springbootweb.model.Person;
import org.apache.ibatis.annotations.Mapper;

//@Mapper
public interface PersonMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Person record);

    int insertSelective(Person record);

    Person selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Person record);

    int updateByPrimaryKey(Person record);
}

在运行主类Application上加@MapperScan("com.mufeng.springbootweb.mapper")

package com.mufeng.springbootweb;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.mufeng.springbootweb.mapper")
public class SpringbootWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebApplication.class, args);
    }

}

运行测试结果

image

1.8 接口和映射文件分开

  • 修改GeneratorMapper.xml 文件中Mapper映射文件生成目标位置, 目标指向resources下的mapper文件夹下
        <!-- 生成 MyBatis 的 Mapper.xml 文件,targetPackage 指定 mapper.xml 文件的包名, targetProject 指定生成的 mapper.xml 放在哪个工程下面 -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
  • 重新运行代码生成插件
image

把之前生成的映射文件删除掉

  • 在application.yml配置文件中需要指定映射文件的位置,这个配置只有接口和映射文件不再同一个包的情况下,才需要指定
mybatis:
  mapper-locations: classpath:mapper/*.xml

2. SpringBoot的事务支持

SpringBoot 使用事务非常简单,底层依然采用的是Spring本身提供的事务管理

  • 在入口类中使用注解@EnableTransactionManagement 开启事务支持

  • 在访问数据库的Service方法上添加注解@Transactional即可

在PersonController中添加更新用户的方法
    @RequestMapping(value = "/springboot/updatePersonById")
    @ResponseBody
    public Object updatePersonById(){
        int count = 0;
        try{
            Person person = new Person();
            person.setId(1);
            person.setName("MuFeng_update");
            person.setAge(20);
            count = personService.updatePersonById(person);
        }catch (Exception e){
            e.printStackTrace();
            return "fail";
        }
        return count;
    }
在PersonService接口中添加更新用户的方法
    /**
     * 根据用户id更新用户信息
     * @param person
     * @return
     */
    int updatePersonById(Person person);
在PersonServiceImpl接口实现类中更新用户信息方法进行实现,并主动制造一个异常抛出
    @Override
    public int updatePersonById(Person person) {
        int updateCount = personMapper.updateByPrimaryKeySelective(person);
        System.out.println("更新结果:" + updateCount);
        //在此构造一个除数为 0 的异常,测试事务是否起作用
        int a = 10/0;
        return updateCount;
    }
运行并测试未开启事务的情况
image
image

抛出了异常但是数据修改成功了,我们需要做的是在动作出现异常时,所有的增删改的操作都要回滚

在PersonServiceImpl更新的实现方法上添加@Transactional注解
    @Override
    @Transactional
    public int updatePersonById(Person person) {
        int updateCount = personMapper.updateByPrimaryKeySelective(person);
        System.out.println("更新结果:" + updateCount);
        //在此构造一个除数为 0 的异常,测试事务是否起作用
        int a = 10/0;
        return updateCount;
    }
在Application类上加@EnableTransactionManagement注解开始事务支持
@SpringBootApplication
@MapperScan("com.mufeng.springbootweb.mapper")
@EnableTransactionManagement
public class SpringbootWebApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootWebApplication.class, args);
    }

}

@EnableTransactionManagement是可选的,但是业务方法上必须添加@Transactional事务才生效

修改Controller的修改用户信息的代码
@RequestMapping(value = "/springboot/updatePersonById")
    @ResponseBody
    public Object updatePersonById(){
        int count = 0;
        try{
            Person person = new Person();
            person.setId(1);
            person.setName("MuFeng_update");
            person.setAge(25);
            count = personService.updatePersonById(person);
        }catch (Exception e){
            e.printStackTrace();
            return "fail";
        }
        return count;
    }
运行测试
image
image

同样抛出了异常,但是数据库的年龄信息还是之前的20,并没有被修改,说明我们的事务开启成功了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容