MyBatis:Mybatis注解实现 一对一,一对多,多对多

项目依赖

<!-- 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数组中添加上即可。

 

文章转载至:https://blog.csdn.net/desert568/article/details/79079151 

posted @ 2022-08-26 10:04  怒吼的萝卜  阅读(938)  评论(0)    收藏  举报