项目依赖
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
场景:一对一
实体类:
// Person类内引用Card类
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Person{
private String pname;
private int pid;
private int page;
// 引用Card类
private Card card;
}
// Card类
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Card{
// 外键关联Person的pid
private int uid;
private String cnumber;
}
Mapper接口:
// Person的Mapper接口
@Mapper
@Repository
public interface PersoneMapper {
// 映射关系 (方便复用)
// 设置Persone中的Card调用的Mapper和接口方法, 设置"映射Card中uid的字段"为pid
// one=@One 表示映射的为一个实体,即一对一的方式
// 1、FetchType.LAZY:懒加载(延迟加载),加载一个实体时,定义懒加载的属性不会马上从数据库中加载;一般为加载一对多时需要设置。
// 2、FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载;一般为加载一对一时需要设置。
@Results(id="personMap", value={
@Result(id=true,column="pid",property="pid"),
@Result(column="pname",property="pname"),
@Result(column="page",property="page"),
@Result(column="pid",property="card",
one=@One(select="com.desert.dao.CardMapper.getCardById",fetchType= FetchType.EAGER))
})
public Person selectOne();
@Select("select * from person where pid = #{pid}")
// 引用上面的映射关系
@ResultMap(value="personMap")
public Person getPersonById(int pid);
}
// Card的Mapper接口
@Mapper
@Repository
public interface CardMapper {
// uid为Person的pid关联外键
@Select("select * from card where uid = #{uid} ")
public Card getCardById(int uid);
}
单元测试:
@Test //一对一
public void Testonttoone() throws IOException {
// 创建数据连接
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config"));
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取Mapper接口
PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class);
// 根据id查询Person对象,同时根据一对多获得到关联的Card对象
Person person = personMapper.getPersonById(1);
// 打印结果
System.out.println(person);
// 查看Persion内引用的Card是否有值
System.out.println(person.getCard().getCnumber());
// 关闭数据连接
sqlSession.close();
}
场景:一对多
实体类:
// Provinces类内引用Citys类集合
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Provinces{
private String pname;
private int pid;
private int page;
// 引用Citys类的集合
private Set<Citys> citysSet;
}
// Citys类
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Citys{
private int cid;
private String cname;
// 外键关联Provinces的pid (因为是一对多, 所以多个Citys会对应一个Provinces)
private int pid;
}
Mapper接口:
// Provinces的Mapper接口
@Mapper
@Repository
public interface ProvincesMapper {
// 映射关系 (方便复用)
// 设置Provinces中的Citys调用的Mapper和接口方法, 设置"映射Citys中pid的字段"为pid
// many=@Many 表示映射的为多个实体,即一对多或者多对多的方式
// 1、FetchType.LAZY:懒加载(延迟加载),加载一个实体时,定义懒加载的属性不会马上从数据库中加载;一般为加载一对多时需要设置。
// 2、FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载;一般为加载一对一时需要设置。
@Results(id="provincesMap", value={
@Result(id=true,column="pid",property="pid"),
@Result(column="pname",property="pname"),
@Result(column="pid",property="citysSet",
many=@Many(select="com.desert.dao.CityMapper.getCityByPid",fetchType= FetchType.LAZY))
})
public Provinces selectOne();
@Select("select * from provinces where pid = #{pid}")
// 引用上面的映射关系
@ResultMap(value="provincesMap")
public Provinces getProvincesById(int pid);
}
// City的Mapper接口
@Mapper
@Repository
public interface CityMapper {
// pid就是对应Provinces的pid字段
@Select("select * from city where pid=#{pid}")
public List<Citys> getCityByPid(int pid);
}
单元测试:
@Test //一对多
public void Testonttomany() throws IOException {
// 建立SqlSession连接会话
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config"));
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取Mapper
ProvincesMapper provincesMapper = sqlSession.getMapper(ProvincesMapper.class);
// 调用接口
Provinces provinces = provincesMapper.getProvincesById(1);
// 打印结果
System.out.println(provinces.getPname());
// 查看City集合是否有值
for (Citys citys : provinces.getCitysSet()) {
System.out.println(citys.getCname());
}
// 关闭连接
sqlSession.close();
}
场景:多对多
实体类:
// User类内引用Roles类集合
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class User{
private int uid;
private String uname;
// roles对象
private Set<Roles> roles;
}
// Roles类内引用Powers类集合
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Roles{
private int rid;
private String rname;
// 关联Users的uid
private int uid;
// power类集合
private Set<Powers> powers;
}
// Powers类
@Data
@AllArgsConstructor
@NoArgsConstructor
// 此注解必须标注!否则会报错!具体看文章结尾
@JsonIgnoreProperties(value = {"handler"})
public class Powers{
private int pid;
private String pname;
// 关联Roles类的rid字段
private int rid;
}
Mapper接口:
// User的Mapper接口
@Mapper
@Repository
public interface UserMapper {
//模糊查询获取用户集合
@Select("select * from users where uname like %#{uname}%")
// 这里是简化的写法
@Results({
@Result(id=true,column="uid",property="uid"),
@Result(column="uname",property="uname"),
@Result(column="uid",property="roles",
many=@Many(select="com.desert.dao.RolesMapper.getRoleListByUid",fetchType= FetchType.LAZY))
})
public List<Users> getUserListByName(String uname);
}
// Roles的Mapper接口
@Mapper
@Repository
public interface RolesMapper {
// 根据Uid获取Roles对象集合
@Select("select * from roles where uid = #{uid}")
// 这里是简化的写法
@Results({
@Result(id=true,column="rid",property="rid"),
@Result(column="rname",property="rname"),
@Result(column="uid",property="uid"),
@Result(column="rid",property="roles",
many=@Many(select="com.desert.dao.PowersMapper.getPowerListByRid",fetchType= FetchType.LAZY))
})
public List<Roles> getRoleListByUid(int uid);
}
// Powers的Mapper接口
@Mapper
@Repository
public interface PowersMapper {
//根据rid获取Powers对象集合
@Select("select * from powers where rid = #{rid}")
// 这里是简化的写法
@Results({
@Result(id=true,column="pid",property="pid"),
@Result(column="pname",property="pname"),
@Result(column="rid",property="rid")
})
public List<Powers> getPowerListByRid(int rid);
}
单元测试:
@Test //多对多
public void Testmanytomany() throws IOException {
// 建立SqlSession会话连接
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config"));
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获取UserMapper接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 调用接口
List<Users> users = userMapper.getUserListByName("明");
// 打印结果
for(Users user : users){
System.out.println(user.getUname());
// 查看Roles集合是否为空
for (Roles role : user.getRoles()) {
System.out.println(role.getRname());
// 查看Powers集合是否为空
for(Powers power : role.getPowers){
System.out.println(power.getPname());
}
}
}
// 关闭连接
sqlSession.close();
}
报错处理!!
报错信息如下:
找不到类org.apache.ibatis.executor.loader.javassist.Javassis的序列化程序
Type definition error: [simple type, class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.tianzhengyuan.common.utils.Result["data"]->java.util.ArrayList[0]->com.tianzhengyuan.common.dto.MeetingDTO_$$_jvst639_0["handler"])
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.tianzhengyuan.common.utils.Result["data"]->java.util.ArrayList[0]->com.tianzhengyuan.common.dto.MeetingDTO_$$_jvst639_0["handler"])
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:293)
at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:103)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:290)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:119)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:645)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:750)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.tianzhengyuan.common.xss.XssFilter.doFilter(XssFilter.java:24)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
at org.apache.catalina.core.StandardContextValve.__invoke(StandardContextValve.java:96)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:41002)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
原因:
Mybatis级联查询时,会生成handler属性结构数据!
解决:
在相关的映射实体类上标注注解
@JsonIgnoreProperties(value = {"handler"})
注解的作用在于告诉jsonplug组件,在将代理对象转换为json对象时,忽略value对应的数组中的属性,即"handler"属性。
如果需要忽略其他属性("hibernateLazyInitializer","handler","fieldHandler"),直接在value数组中添加上即可。
作者:怒吼的萝卜