technology-integration(四)---SpringBoot整合Mybatis

Mybatis

Mybatis作为本人最喜欢的持久层框架,当然得整合进来啦!!!

  • Mybatis需要程序猿自己编写增删改查所需要的SQL语句,而Hibernate可以通过对象关系模型实现对数据库的操作,可以完全脱离SQL,但正因如此Mybatis可以根据业务最大程度优化SQL语句来达到良好的性能。Mybatis也有第三方工具提供类似Hibernate的功能,比如Mybatis-plus,这里暂时不介绍
  • Mybatis的可移植性非常一般...虽说有支持,但局限性还是比较大的,而Hibernate所使用的HQL则可以转换成对应数据库的SQL。虽说好像很厉害,但一般来说换数据库的操作还是比较少的。
  • 还有其他区别,但我就不写

SpringBoot整合Mybatis

添加jar依赖---pom.xml

    org.mybatis.spring.boot
    mybatis-spring-boot-starter
    1.3.2


    mysql
    mysql-connector-java
     runtime

导入Mybatis相关依赖,mybatis-spring-boot-starter是把Mybatis.jar和mybatis-spring.jar整合在了一起。

配置Mybatis

配置Mybatis常用两种方式,一种使用SpringBoot配置文件方式配置数据库连接及Mybatis;另一种则是使用java config配置(代码方式),这也是我比较喜欢的一种方式。

application.yml方式

1、在application.yml配置数据库连接信息及Mybatis

spring:
  datasource:
      data-source-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/technology-integration
      username: root
      password: 123456

mybatis:
  mapper-locations: classpath:mapping/ *.xml
  type-aliases-package: com.viu.technology.po 

2、在TechnologyIntegrationApplication.class中添加MapperScan注解,该注解用于扫描Mapper接口所在的包

@SpringBootApplication
@MapperScan("com.viu.technology.mapper")
public class TechnologyIntegrationApplication implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(TechnologyIntegrationApplication.class, args);
    }
}

java config方式

在config.datasource包中创建MybatisConfig类


@Configuration
@MapperScan("com.viu.technology.mapper") 
public class MybatisConfig extends HikariConfig{

    @Autowired
    private Environment env;

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "datasource1.jdbc")
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(env.getProperty("datasource1.jdbc.driverClassName"));
        dataSource.setJdbcUrl(env.getProperty("datasource1.jdbc.url"));
        dataSource.setUsername(env.getProperty("datasource1.jdbc.username"));
        dataSource.setPassword(env.getProperty("datasource1.jdbc.password"));
        dataSource.setMaximumPoolSize(100);
        dataSource.setPoolName("hikari-");
        return dataSource;
    }

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory( DataSource dataSource) throws Exception {
        SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
        fb.setDataSource(dataSource);
        fb.setTypeAliasesPackage("com.viu.technology.po");
        fb.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/*.xml"));
        return fb.getObject();
    }
}

application.yml

datasource1.jdbc:
  driverClassName: com.mysql.jdbc.Driver
  jdbcUrl: jdbc:mysql://localhost:3306/technology-integration
  username: root
  password: 123456
  min-idle: 10
  • @MapperScan("com.viu.technology.mapper") :扫描Mapper接口所在的包
  • @Primary :在拥有多个同类型Bean时,SpringBoot自动注入会选择带有该注解的Bean,否则自动注入将会提示注入失败,原因是因为IOC中拥有多个同类型的Bean,而SpringBoot无法判断使用哪个Bean,导致异常发生。
  • Environment:可获取到所有的配置资源
  • @ConfigurationProperties(prefix = "datasource1.jdbc") :加载application..yml以datasource1.jdbc开头的配置
  • fb.setTypeAliasesPackage("com.viu.technology.po"):设置该包下的所有类可以在mapper.xml中直接使用类名而非全类名

这里需要使用@Primary注解是因为SpringBoot默认配置了SqlSessionFactory和DataSource,即SpringBoot的IOC容器启动时会自动将这两个Bean注入进来,而我们选择java config方式配置数据库时则会与SpringBoot默认配置的DataSource Bean产生冲突,@Primary注解则是用来告诉容器优先选择java config配置的Bean。不过该方式并不是最好的解决方案,因为SpringBoot默认配置的DataSource Bean我们并没有使用,我们可以在启动类中取消SpringBoot自动配置的DataSource,这样就不需要加@Primary注解,还能提高应用的启动速度。

@SpringBootApplication
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class TechnologyIntegrationApplication implements CommandLineRunner {
    public static void main(String[] args) {
        SpringApplication.run(TechnologyIntegrationApplication.class, args);
    }
}



SpringBoot配置Mybatis就完成了,接下来写个注册用户的案例



步骤:

  1. 创建一条新的用户数据,userId使用Mybatis生成UUID进行插入,并返回
  2. 创建一条新的用户角色数据,简单业务,ID自增
  3. 创建成功并返回

编写SQL语句

UserMapper.xml

selectKey 会将MySQL select的结果放入到传入的model的主键里面,
keyProperty 对应的model中的主键的属性名,这里是 user 中的id,因为它跟数据库的主键对应
order AFTER 表示 SELECT在insert执行之后执行,多用与自增主键;
BEFORE 表示 SELECT在insert执行之前执行, 这种适合那种主键不是自增的类型


    
      select replace(uuid(), '-', '') as id from dual
    
    insert into t_user (id,name, phone,password)
    values (#{id},#{name}, #{phone}, #{password}
      )
  

RoleMapper.xml


    insert into t_role (role_name, user_id)
    values ( #{roleName,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER})
  

编写DAO类

在项目的dao包创建UserDao接口类

public interface UserDao {
    User selectByPrimaryKey(String id);
}

@Repository
public class UserDaoImpl implements UserDao{
    @Autowired
    private UserMapper userMapper;

    public User selectByPrimaryKey(String id) {
        return userMapper.selectByPrimaryKey(id);
    }
}
public interface RoleDao {
    Role insertRole(Role role);
}

@Repository
public class RoleDaoImpl implements RoleDao {
    @Autowired
    private RoleMapper roleMapper;

    @Override
    public Role insertRole(Role role) {
        if (roleMapper.insert(role)>0) {
            return role;
        }
        return null;
    }
}

UserDao的实现类需要加入@Repository,一是为了把该类注册为Bean,二是该注解支持处理数据库操作产生的异常

编写Service类

public interface UserService {
    User registerUser(User user);
}

@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userDao;

    @Transactional
    @Override
    public User registerUser(User user) {
        User userRes = userDao.insertUser(user);
        Role roleRes = roleDao.insertRole(new Role("普通群众", user.getId()));
        List list = new ArrayList();
        list.add(roleRes);

        if (null != userRes && null != roleRes) {
            userRes.setRoles(list);
            return user;
        }
        return null;
    }
}

编写Result类(用于统一返回结果)

public class Result {

    private String code;
    private String msg;
    private T data;

    public Result() {}

    public Result(ResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.data = data;
    }

    public Result(ResultCode resultCode) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
    }

    public static Result success() {return new Result(ResultCode.SUCCESS);}
    public static Result success(Object data) {return new Result(ResultCode.SUCCESS, data); }
    public static Result fail(ResultCode resultCode,String msg){return new Result(resultCode, msg);}
    public static Result fail(ResultCode resultCode){return new Result(resultCode);}

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
public class ResultCode {

    private String code;

    private String msg;

    public static ResultCode SUCCESS = new ResultCode("0000", "success");
    public static ResultCode DATA_CHECK_FAILURE = new ResultCode("1000", "数据校验失败");
    public static ResultCode DATA_INSERT_FAILURE = new ResultCode("1001", "数据插入失败");
    public static ResultCode SECKILL_END = new ResultCode("2001", "秒杀结束");
    public static ResultCode SMS_SEND_FAIL = new ResultCode("3001", "短信发送失败");
    public static ResultCode SMS_CODE_VALID_FAIL = new ResultCode("3002", "短信校验失败");
    public static ResultCode SMS_QUERY_NOT_FOUND = new ResultCode("3003", "找不到该短信");
    public static ResultCode USER_REGISTER_FIAL = new ResultCode("4000", "用户注册失败");
    public static ResultCode USER_LOGIN_FIAL = new ResultCode("401", "用户身份验证失败");
    public static ResultCode USER_PERMISSION_DENIED = new ResultCode("403", "用户账号权限不足");

    public ResultCode(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {return code;}

    public void setCode(String code) {this.code = code;}

    public String getMsg() {return msg;}

    public void setMsg(String msg) {this.msg = msg;}
}

编写Controller类

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserServiceImpl userService;

    @PostMapping("/register")
    public Result insertUser(@RequestBody User user) {
        User result = userService.registerUser(user);
        if (null != result) {
            return Result.success(result);
        }
        return Result.fail(ResultCode.USER_REGISTER_FIAL);
    }
}

测试

启动SpringBoot应用,在postman中测试该地址


technology-integration(四)---SpringBoot整合Mybatis_第1张图片
image.png


更多文章请关注该 technology-integration全面解析专题

你可能感兴趣的:(technology-integration(四)---SpringBoot整合Mybatis)