zoukankan      html  css  js  c++  java
  • Po类设计

    0、承接MySQL 表设计,同样地,这篇博客中一部分内容是Deolin的个人观点和习惯。

    1、一般Po类的域是和DB表字段一一对应的,

    而由于每个信息表和关联表都有id、insert_time、update_time、remove_time字段,

    所以可以提取一个PoCommon类供具体的Po类继承

    abstract public class PoCommon {
    
        private Integer id;
    
        private Date insert_time;
    
        private Date update_time;
    
        private Date remove_time;
    
        // getters ,setters and toString here
    
    }
    class StudentPo extends PoCommon {
    
        private String name;
    
        // getters, setters and toString here
    
    }

    2、插入行为中,每个Po类都会指定insert_time, del_flag

    修改行为中,每个Po类都会指定update_time

    移除行为中,每个Po类都会指定del_flag

    所以可以追加三个静态工厂方法

        public static <T extends PoCommon> T forInsert(Class<T> clazz) {
            T po;
            try {
                po = clazz.newInstance();
            } catch (InstantiationException e) {
                return null;
            } catch (IllegalAccessException e) {
                return null;
            }
            // id是自增的
            po.setInsert_time(new Date());
            return po;
        }
    
        public static <T extends PoCommon> T forUpdate(Class<T> clazz, Integer id) {
            T po;
            try {
                po = clazz.newInstance();
            } catch (InstantiationException e) {
                return null;
            } catch (IllegalAccessException e) {
                return null;
            }
            po.setId(id);
            po.setUpdate_time(new Date());
            return po;
        }
    
        public static <T extends PoCommon> T forRemove(Class<T> clazz, Integer id) {
            T po;
            try {
                po = clazz.newInstance();
            } catch (InstantiationException e) {
                return null;
            } catch (IllegalAccessException e) {
                return null;
            }
            po.setId(id);
            po.setRemove_time(new Date());
            return po;
        }

    业务层获得了具体表的Po对象以后,就可以往里面set业务上的数据了。

    StudentPo po = PoCommon.forInsert(Student.class);
    po.setName("Deolin");

    3、增/改/移除操作因为是原子操作,可以用Po类,

    而查表操作用Po类则不太适合。

    因为,对于业务层而言,查到insert_time, update_time, remove_time是没有意义的

    这样的操作需要自定义的持久层对象(Cpo,custom persistence object)(为了类名短一点,Deolin定的缩写...)

    class StudentCpo {
    
        private Integer id;
    
        private String name;
    
        // getters, setters and toString() here
        
    }

    可以Cpo不再继承与PoCommon,id域被放入了自己的内部,也不需要静态工厂方法了,因为Mybatis框架会把结果集的字段名注入到Cpo对象中。

    4、查表操作有时为了不多次查表,所以会出现一些多表查询,主要是两个数据实体一连结一情况,

    这种情况更加需要使用Cpo类

    SELECT person.id, person.name, student.grade as student_grade, school_address
    FROM person, student, school
    WHERE person.id = student.id
    AND person.remove_time IS NULL
    AND student.remove_time IS NULL
    class PersonCpo {
    
        private String id;
    
        private String name;
    
        private String student_grade;
    
        // getters, setters and toString here
    
    }

    由于业务上child只是与person一一对应的拓展表,结果集的主体还是person,所以选择了PersonCpo作为命名。

    5、至于多表查询中两个数据实体一连结多的情况,则需要两个Cpo了

    SELECT school.id, school.name,
    student.name AS one_student_name, student.age AS one_student_age
    FROM school, student
    WHERE school.id=10086
    AND student.for_school=school.id
    AND school.remove_time IS NULL
    AND student.remove_time IS NULL

    这个需求是查出10086号学校的校名,和每一个学生的名字、年龄(假设这里学生表有name和age字段了),

    那么两个Cpo可以这么定义

    public class StudentCpo {
    
        private String one_student_name;
    
        private Integer one_student_age;
    
        // getters, setters, toString here  
    
    }
    public class SchoolCpo {
    
        private Integer id;
    
        private String name;
    
        private List<StudentCpo> studentCpos;
    
        // getters, setters, toString here  
    
    }

    首先,如果还像4、那样定义一个有学生信息的school是不合适的,因为这里会有很多学生,会产生很多schoolCpo,

    那么schoolCpo里面的域[id]和域[name]等于产生了很多份,造成了毫无必要的内存浪费,

    所以在schoolCpo设计了一个List类型的域,这样一来schoolCpo对象只有一个,域[id]和域[name]只有一份。

    指的注意的是,这样的设计需要在statement的<select>标签上指定resultMap属性,并在用上<collection>标签

    但是这样设计可能有一些无法避免的问题,

    只要在持久层存在一个SQL比较独特的statement,

    那就需要专门写一个Cpo为它服务(如果是一连结多的话,需要至少2个Cpo),

    这些Cpo是很难为其他statement复用的,一旦那个SQL文SELECT后面的东西改了,这些Cpo也得跟着改。

    实际上问题的根源在于为什么会出现这样这样statement,

    业务层完全可以调用2个statement,第一个取学校信息,映射到学校Cpo(只去除3个time的Cpo复用性还是很高的),

    第二个取学生信息,映射到学生Cpo的List,分别调用完之后转换一个Map<String, Object>就可以返回给控制层了。

    这样做的缺点,是会有两次数据库请求,可能是出于性能的考虑,业务层才会需要独特的SQL。

    以上便是出现复杂的查表需求时,持久层可以采取的两个方法,总结一下

    Mapper中声明一个特殊的statement,为这个statement专门写几个Cpo,优点是一次查表,而且业务层代码精炼,持久层的返回值可以直接向上返回;缺点是Cpo们和statement耦合了。

    Mapper中声明若干个statement拆分简化需求,用复用性号的Cpo作为结果对象,优缺点跟上一条相反

  • 相关阅读:
    typeof检测几种较为特殊的值与Boolean强制转换哪几种值为false Amy
    类型检测 Amy
    JS基本概念 Amy
    JS导入文件与CSS导入文件的不同 Amy
    JS运行环境 Amy
    主流浏览器及其渲染引擎 Amy
    JS引用类型 Amy
    同名函数的覆盖问题 Amy
    JS变量、作用域和内存问题 Amy
    HTTP协议学习(1)
  • 原文地址:https://www.cnblogs.com/deolin/p/7353466.html
Copyright © 2011-2022 走看看