Mybatis
引入Mybatis maven
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
可以看到其中引用到的各种相关包
【这里一定要注意。mysql的版本。现在默认都是8.0以上。会有很多未知的坑。我们需要把版本改到之前的版本。比如5.1.18】
<!-- Mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.18</version>
<scope>runtime</scope>
</dependency>
在mysql8.0以上版本的时候都会提示你com.mysql.jdbc.Driver已经过期。需要使用com.mysql.cj.jdbc.Driver,
修改完成后我们看看yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://119.3.223.115:3306/test
username: root
password: root123
type: com.alibaba.druid.pool.DruidDataSource
mybatis:
mapper-locations: classpath:mapping/*.xml
type-aliases-package: com.example.smybatis.model
我们新建一个这样的结构
其中在generator下新建一个generatorConfig.xml的文件,注意一定要定义一个classPathEntry来加载本地的mysql驱动包
<?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>
<!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->
<classPathEntry location="D:\JAVA\Maven\apache-maven-3.3.9-bin\apache-maven-3.3.9\.m2\repository\mysql\mysql-connector-java\5.1.18\mysql-connector-java-5.1.18.jar"/>
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--数据库链接URL,用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://119.3.223.115:3306/test?charset=utf8mb4" userId="root" password="root123">
</jdbcConnection>
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成模型的包名和位置-->
<javaModelGenerator targetPackage="com.atlyb.mybatisdemo.model" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 生成映射文件的包名和位置-->
<sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources">
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<!-- 生成DAO的包名和位置-->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.atlyb.mybatisdemo.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
<table tableName="person" domainObjectName="Person" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
</context>
</generatorConfiguration>
为了使用这个generetor.xml的文件我们需要增加一个插件
<!-- mybatis generator 自动生成代码插件 -->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
<overwrite>true</overwrite>
<verbose>true</verbose>
</configuration>
</plugin>
1)点击run-Edit Configurations
2)添加配置
在CommandLine添加mybatis-generator:generate -e
3)运行
运行日志如下
好的。我们再来看看现在的结构,
生成了我们刚才定义的三个文件的代码。
使用
按照我们定义的曾经关系:
-
controller文件夹写和页面的交互
-
service写业务逻辑
-
mapper就是dao层,写数据库操作
-
model写实体类,和数据库映射的或者需要使用到的其他类
-
mapping写映射关系
1、我们需要新增MapperScan标签
package com.atlyb.mybatisdemo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.atlyb.mybatisdemo.mapper")
public class MybatisdemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisdemoApplication.class, args);
}
}
回忆一下MapperScan的作用:
在SpringBoot中集成MyBatis,可以在mapper接口上添加@Mapper注解,将mapper注入到Spring,
但是如果每一给mapper都添加@mapper注解会很麻烦,这时可以使用@MapperScan注解来扫描包。
经测试发现,@MapperScan注解只会扫描包中的接口,不会扫描类,所以可以在包中写Provider类。
@MapperScan(“com.demo.mapper”):扫描指定包中的接口
@MapperScan("com.demo..mapper"):一个代表任意字符串,
但只代表一级包,比如可以扫到com.demo.aaa.mapper,不能扫到com.demo.aaa.bbb.mapper
@MapperScan(“com.demo.**.mapper”):两个*代表任意个包,比如可以扫到com.demo.aaa.mapper,
也可以扫到com.demo.aaa.bbb.mapper
使用 @Mapper,最终 Mybatis 会有一个拦截器,会自动的把 @Mapper 注解的接口生成动态代理类。 这点可以在
MapperRegistry 类中的源代 码中查看。@Mapper 注解针对的是一个一个的类, 相当于是一个一个 Mapper.xml
文件。而一个接口一个接口的使用 @Mapper,太麻烦了,于是 @MapperScan 就应用而生了。 @MapperScan
配置一个或多个包路径,自动的扫描这些包路径下的类,自动的为它们生成代理类。使用 @MapperScan 注解,将会生成 MapperFactoryBean, 如果没有标注 @MapperScan 也就是没有
MapperFactoryBean 的实例,就走 @Import 里面的配置, 具体可以在
AutoConfiguredMapperScannerRegistrar 和 MybatisAutoConfiguration
类中查看源代码进行分析。
2、controller层
记得增加@RestController注解以完成标记Controller以及ResponseBody的作用。
package com.atlyb.mybatisdemo.controller;
import com.atlyb.mybatisdemo.model.Person;
import com.atlyb.mybatisdemo.service.PersonS;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
public class PersonC {
@Resource
private PersonS personS;
//增加
@PostMapping(value="/person")
public int savePerson(@RequestParam("id") Integer id, @RequestParam("age") Integer age, @RequestParam("name") String name){
return personS.savePerson(id,age,name);
}
//访问
@GetMapping(value="/person/{id}")
public Person getPerson(@PathVariable("id") Integer id){
return personS.getPerson(id);
}
//修改
@PutMapping(value="/person/{id}")
public int updatePerson(@PathVariable("id") Integer id,@RequestParam("age") Integer age,@RequestParam("name") String name){
return personS.updatePerson(id,age,name);
}
//删除
@DeleteMapping(value="/person/{id}")
public int deletePerson(@PathVariable("id")Integer id){
return personS.deletePerson(id);
}
}
3、service层
@Service注解区别服务层。并且标记@Resource来注入相关的类
package com.atlyb.mybatisdemo.service;
import com.atlyb.mybatisdemo.mapper.PersonMapper;
import com.atlyb.mybatisdemo.model.Person;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class PersonS {
@Resource
private PersonMapper personM;
public Person getPerson(Integer id){
return personM.selectByPrimaryKey(id);
}
public int savePerson(Integer id,Integer age,String name){
Person p = new Person();
p.setId(id);
p.setAge(age);
p.setName(name);
return personM.insert(p);
}
public int updatePerson(Integer id,Integer age,String name){
Person p = personM.selectByPrimaryKey(id);
p.setAge(age);
p.setName(name);
return personM.updateByPrimaryKey(p);
}
public int deletePerson(Integer id){
return personM.deleteByPrimaryKey(id);
}
}
此处我们都选择了@Resource而不是@Autowired注解,是因为:
spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按
byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;@Autowired 与@Resource的区别:
1、@Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false)
,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:@Autowired()@Qualifier("baseDao") privateBaseDao baseDao;
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao") privateBaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。