在test包下新建测试类PorscheMapperTest
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:application.xml") public class PorscheMapperTest { @Resource private PorscheMapper porscheMapper; @Test public void getPorscheById(){ Porsche panamera = porscheMapper.getPorscheById(1); System.out.println("查询到的内容为:" + panamera); } } 复制代码
执行测试
控制台成功查询出id为1的Porsche对象,框架搭建成功
二、通用Mapper实现基本增删改查-BaseMapper
2.1 集成通用Mapper
首先在pom.xml中通用Mapper的依赖
<dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper</artifactId> <version>4.1.5</version> </dependency> 复制代码
接着需要修改Spring配置文件
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--其他内容不变--> <!--Mapper XML的配置注销,使用通用Mapper就不再需要Mapper XML了--> <!--<property name="mapperLocations" value="classpath:mappers/*.xml"></property>--> </bean> <!--Dao层接口加入到Spring容器, 使用tk包下面的MapperScannerConfigurer,原来是org开头--> <bean id="mapperScannerConfigurer" class="tk.mybatis.spring.mapper.MapperScannerConfigurer"> <!--其他内容不变--> <property name="basePackage" value="com.citi.mapper"></property> </bean> 复制代码
删除mapper文件夹下的PorscheMapper.xml,因为使用通用Mapper不需要Mapper XML文件
2.2 selectOne () 方法
修改PorscheMapper接口及TeacherMapper接口,需要继承通用Mapper提供的Mapper接口,泛型为实体类类型,删除原有的方法
public interface TeacherMapper extends Mapper<Teacher> { } 复制代码
public interface PorscheMapper extends Mapper<Porsche> { } 复制代码
因为需要在声明式事务中调用Service层,新建service及impl两个包,增加PorscheServic接口PorscheServiceImpl实现类
public interface PorscheService { Porsche getOne(Porsche record); } 复制代码
@Service public class PorscheServiceImpl implements PorscheService { @Autowired private PorscheMapper porscheMapper; @Override public Porsche getOne(Porsche record) { return porscheMapper.selectOne(record); } } 复制代码
查看看通用Mapper源码
- BaseMapper:基本操作
- ExampleMapper:Example封装查询条件,实现QBC查询,QBC(Query By Criteria)查询
- RowBoundsMapper是做分页查询的
新建PorscheService接口的测试类
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:application.xml") public class PorscheServiceTest { @Autowired private PorscheService porscheService; @Test public void getOne() { // 构造查询条件 Porsche record = new Porsche(); record.setPorName("Cayenne"); record.setPorPrice(910000d); // 执行查询 Porsche porsche = porscheService.getOne(record); System.out.println("查询到的内容为:" + porsche); } } 复制代码
执行测试
根据控制台输出的SQL语句可以看出设置的查询条件全部生效,继承的通用Mapper的方法可用。
实体类封装查询条件的规则
- 使用非空的值生成WHERE子句
- 在条件表达式中使用 “=” 进行比较 如果根据查询条件返回多个结果则会报异常,将PorscheServiceTest中getOne方法中的set语句注释掉,再次执行测试
selectOne要求只返回一个结果
2.3 @Table和@Column注解
由于通用Mapper根据实体类生成对应的SQL语句,这就要求实体类的类名和属性最好与数据库表名和字段一致,如果不一致则会导致通用Mapper中提供的方法无法使用,以Teacher实体类和t_teacher表为例。
service包中新建TeacherService接口和TeacherServiceImpl实现类,新增getOne方法,调用TeacherMapper的selectOne方法
public interface TeacherService { Teacher getOne(Teacher record); } 复制代码
@Service public class TeacherServiceImpl implements TeacherService { @Autowired private TeacherMapper teacherMapper; @Override public Teacher getOne(Teacher record) { return teacherMapper.selectOne(record); } } 复制代码
test包下增加TeacherService接口的测试类TeacherServiceTest
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:application.xml") public class TeacherServiceTest { @Autowired private TeacherService teacherService; @Test public void getOne() { // 构造查询条件 Teacher record = new Teacher(); record.setGrade("三年二班"); record.setName("stark"); Teacher teacher = teacherService.getOne(record); System.out.println(teacher); } } 复制代码
执行测试
控制台输出SQL执行报错信息,可以看到执行的SQL语句中查询的表与字段与数据库中的t_teacher不一致。
通用Mapper可以通过在类名上增加@Table注解使类名和数据库表名保持一致,@Column注解可以使实体类属性和数据库字段名保持一致,使用这两个注解更改Teacher实体类
@Data @Table(name = "t_teacher") public class Teacher { private Integer id; @Column(name = "teacher_name") private String name; // 执教的年级 @Column(name = "class_name") private String grade; private String address; private Date birthDate; } 复制代码
再次执行测试
控制台成功输出grade属性为三年二班name为stark的Teacher对象。
plus:实体类属性birthDate与表字段birth_date可以通过mybatis-config.xml中的settings标签配置开启驼峰命名转换解决。
2.4 select 相关方法与 @Id 注解
// 根据实体中的属性值进行查询,返回List列表,查询条件使用等号 List<T> select(T record); // 查询全部结果,返回List列表 List<T> selectAll(); // 根据实体中的属性查询总数,返回int类型,查询条件使用等号 int selectCount(T record); // 根据主键字段进行查询,方法参数必须包含完整的主键属性,返回一个实体类,查询条件使用等号 T selectByPrimaryKey(Object key); // 根据主键字段查询总数,方法参数必须包含完整的主键属性,返回True或者False查询条件使用等号 boolean existsWithPrimaryKey(Object key); 复制代码
2.4.1 测试 selectByPrimaryKey 方法
在PorscheService和PorscheServiceImpl中定义和实现方法getPorscheById
Porsche getPorscheById(Integer id); 复制代码
@Override public Porsche getPorscheById(Integer id) { return porscheMapper.selectByPrimaryKey(id); } 复制代码
在PorscheServiceTest类中增加getPorscheById测试方法
@Test public void getPorscheById(){ Porsche porsche = porscheService.getPorscheById(2); System.out.println("查询到的内容为:" + porsche); } 复制代码
执行测试
控制台输出查询的内容为null,并且执行的SQL语句中WHERE子句后面跟了全部属性作为条件,跟预想的以por_id作为查询条件不同。这是因为实体类中属性中没有显示的标注哪个属性对应数据库中的主键,通用Mapper把所有的字段集合起来当成了一个联合主键
在Porsche实体类上的por_id属性上增加@Id注解,再次执行测试
数据库表的主键与实体类中的por_id属性对应起来,成功查询出数据
2.4.2 测试 existsWithPrimaryKey 方法
在PorscheService和PorscheServiceImpl中定义和实现方法isExists
Boolean isExists(Integer id); 复制代码
@Override public Boolean isExists(Integer id) { return porscheMapper.existsWithPrimaryKey(id); } 复制代码
在PorscheServiceTest类中增加isExists测试方法
@Test public void isExists(){ Integer id = 30; Boolean exists = porscheService.isExists(id); System.out.println("是否存在主键为" + id + "的记录:" + exists); } 复制代码
执行测试
查看控制台输出的SQL语句,通用Mapper根据count函数计算查询到的个数,如果为0就不存在返回False,如果为1就存在返回True。