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
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
     <scope>runtime</scope>
</dependency>

导入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执行之前执行, 这种适合那种主键不是自增的类型

<insert id="insert" parameterType="com.viu.technology.po.User">
    <selectKey keyProperty="id" resultType="string" order="BEFORE">
      select replace(uuid(), '-', '') as id from dual
    </selectKey>
    insert into t_user (id,name, phone,password)
    values (#{id},#{name}, #{phone}, #{password}
      )
  </insert>

RoleMapper.xml

<insert id="insert" parameterType="com.viu.technology.po.Role">
    insert into t_role (role_name, user_id)
    values ( #{roleName,jdbcType=VARCHAR}, #{userId,jdbcType=INTEGER})
  </insert>

编写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<T> {

    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中测试该地址


image.png


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

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

推荐阅读更多精彩内容