记一些问题

来源:互联网 发布:2016网络自制剧排行榜 编辑:程序博客网 时间:2024/06/05 06:42

记一些问题

  • 记一些问题
    • 单词收录
    • 快捷键收录IDEA
    • 用户账户-自然主键
    • 基于Bootstrap的分页工具类
    • PathVariable
      • 地址通配符优先级
    • 继承映射 Mapping inheritance
      • Table per class hierarchy
      • Table per subclass with joins
      • Mixing inheritance strategies 混合继承策略

单词收录

discriminate 分辨,辨别hierarchy 等级制度,分层inheritance 继承polymorphism 多态implicit 含蓄的,不严明的,隐式的explicit 明显的normalize 规范化, 使标准化

快捷键收录(IDEA)

Ctrl+Shift+t 生成测试类Shift+F10 运行测试类的方法Ctrl+U 转到父类Crtl+B 光标跳转(跳到哪里?看情况了)

2017-4-13

用户/账户-自然主键

@Entity@Table(name="peoples")class People {  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)  private Long pid;  @NaturalId(mutable=true)  @Column(nullable=false)  private String name;  @Column(nullable=false, unique=true)  private String email;  private String password;  //头像  String avatar;}

//这里自然主键的设置有什么意义呢?查询会有优化吗?…

可能是这样的,主键Id一般是不知道的,查询时,使用条件查询如where name=”” 或者 email=”“,性能效率不高,所以这里就将name,设置为自然主键,SQL执行顺序为先查找pid,然后再查找用户

这里写图片描述

这里只是定义了一个自然主键, 那么能否定义多个自然主键呢?

用户登录时,能够使用用户名/邮箱登录,如果邮箱也能设为自然主键,那么不论哪种方式?查询效率应该都是很高的。

多个主键也是可以的,但是查询时,如果有多个自然主键时,只使用一个查询,会出现问题.

如下图:

这里写图片描述

使用以下的方式(使用所有自然主键来查询),不会出现问题,但明显与需求不一致了…

//这里查询时,只使用name是不行的...public People findByName(String name) {        Optional<People> option = currentSession().byNaturalId(People.class).using("name", name).using("email", "1849901944@qq.com").loadOptional();        if(option.isPresent()) {            People people = option.get();            log.info(people);            return people;        }        return null;    }

?有没有别的办法内,这里就不知道了..

2017-4-14

Spring MVC 如何从一个控制器跳转到另一个控制器?

在返回的路径地址前加上forward:|reddirect: 来选择是转发还是重定向

如果重定向/转发时,后缀有中文出现的话,最终浏览器地址栏中会出现中文乱码
这里写图片描述

这时需要使用URLEncoder来将编码修改为utf-8

@PostMapping("/login")public String login(People people) throws UnsupportedEncodingException {  log.info(people);  //people = peopleService.findByName(people.getName());  if(people == null)    return "/login";  else {    return String.format("redirect:/people/%s", URLEncoder.encode(people.getName(), "utf-8"));    //return "forward:/people/" + people.getName();  }}

这里写图片描述

用户信息模块想要实现如下的功能:

对于形如people/{params}通配符形URL

  1. 如果params匹配正则表达式[0-9a-b_\u4e00-\u9fa5]*, 则将本参数理解为用户名
  2. 否则理解为要列举所有用户(分页)。符合page-[0-9]*进行分页查询, 若后缀能够解析成整数,则按照具体页数查询,否则默认从第一页开始查询

不如这样:

  1. 参数中有”-“,我们就选择使用分页处理,具体页数从参数中获取,默认为1,每页显示大小默认为20
  2. 没有“-”出现就当成用户处理,这时我们从数据库中查找,有?显示用户信息:用户不存在
<%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><c:set var="request" value="${pageContext.request}"/><c:set var="path" value="${request.contextPath}"/><c:set var="basePath" value="${request.scheme}://${request.serverName}:${request.serverPort}${path}/"/><!--上面这一个可能会出问题 request.scheme为空, 这就不好办了-->//感觉与下面联合起来使用情况好些<c:set var="basePath" value="<%=basePath%>"/>

2017-4-15

基于Bootstrap的分页工具类

需求:正常情况下,需要在当前页左边右边分别有3个候选页,当然也有首页 上一页 下一页 尾页

特殊情况下:

  1. currentPage = 1(第一页/首页) 不显示首页与上一页,显示: 1 2 3 4 下一页 尾页
  2. 1<= currentPage <= 3时, 左边候选个数=currentpage-1;
  3. total-3<=currentPage <= total时, 右边候选个数=total-currentPage;
public class Page<T> {    /*候选个数:左边右边都为3*/    private final static int CANDICATES_SIZE = 3;    private List<T> valueList = new ArrayList<T>();    /*尾页*/    private int endPage;    /*上一页*/    private int prevPage;    /*下一页*/    private int nextPage;    /*当前页*/    private int currentPage;    /*显示候选页*/    private int[] candicates;    public Page(int currentPage,int rows, int total, List<T> valueList) {        this.currentPage = (currentPage < 1) ? 1 : currentPage;        this.valueList = valueList;        endPage = (int)((double)total/rows + 0.5);        nextPage = currentPage + 1;        prevPage = currentPage - 1;        int left = currentPage > CANDICATES_SIZE ? CANDICATES_SIZE : currentPage-1;        int startPage = currentPage - left;        int right = (currentPage + CANDICATES_SIZE) < endPage? CANDICATES_SIZE : endPage-currentPage;        int len = left + right + 1;        candicates = new int[len];        for(int i = 0; i < len; i ++) {            candicates[i] = startPage + i;        }    }}

@PathVariable

这里讲一下@PathVariable,灵活使用确实能够增加开发效率

昨天我将用户列表、用户信息的链接都放到了people/{params}这个通配符里,然后在方法里面判读是列举用户,还是查看单个用户…感觉这样耦合性会有点高,如果现在又要添加一种新的链接类型,那么又要在这个方法里修改了。

今天突然想到Spring中还有这样一种用法:people/page-{page}, 那么含有page-前缀的会被优先匹配到这个地址通配符,显示用户列表,而单个用户的信息,则可以这样people/{name}。

地址通配符优先级

当一个URL地址能够匹配多个地址通配符时,那么是使用哪一个进行匹配呢?

  1. 地址通配符中变量越少、统配符号(*)越少的 优先级高。如:/hotels/{hotel}/* 有一个URL变量和一个统配符号*, 会比/hotels/{hotel}/**优先考虑
  2. 如果URL变量、统配符号(*)相同, 那么长的的会被优先考虑。如:/foo/bar*会比/foo/*优先考虑。

2017-04-16

继承映射 Mapping inheritance

三种方式(158)

  1. 所有类都在一个表中,通过设置一个字段(@DiscriminatorColumn)来进行区分(@DiscriminatorValue)
  2. 每一个类都在一个表中,表之间有主从关系,子类的查询需要查询多个表
  3. 每一个具体类(子类)对应一个表

Table per class hierarchy

@Entity@Table(name="articles")@DiscriminatorColumn(name="type")@DiscriminatorValue("article")public class Article {    @Id @Column(name="id")    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    //发表作者    @JoinColumn(name = "authorid")    @ManyToOne(cascade = CascadeType.REFRESH)    private People author;    //内容    @Lob    private String context;    //发表时间    @Temporal(value= TemporalType.TIMESTAMP)    private Date postTime;    //setter 和 getter 略}
@Entity@DiscriminatorValue("question")public class Question extends Article {    private String title;}
@Entity@DiscriminatorValue("reply")public class Reply extends Reply {}

最終結果如下:

这里写图片描述

这种方式,多态通过一种非规范化的数据库模式来实现。通过一个基于行的识别器来区分超类/子类。

Table per subclass with joins

@Entity@Table(name="articles")@Inheritance(strategy = InheritanceType.JOINED)public class Article {    @Id @Column(name="aid")    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long aid;    //发表作者    @JoinColumn(name = "authorid")    @ManyToOne(cascade = CascadeType.REFRESH)    private People author;    //内容    @Lob    private String context;    //发表时间    @Temporal(value= TemporalType.TIMESTAMP)    private Date postTime;}
@Entity@Table(name="questions")public class Question extends Article {    private String title;}
@Entity@Table(name="replies")@PrimaryKeyJoinColumn(name="rid")public class Reply extends Article {}

细心的人可能会发现Reply类要比Question类多了点东西…

结果如下:

#自动建表SQL语句Hibernate:     create table articles (        aid bigint not null auto_increment,        context longtext,        postTime datetime,        authorid bigint,        primary key (aid)    )Hibernate:     create table questions (        title varchar(255),        aid bigint not null,        primary key (aid)    )Hibernate:     create table replies (        rid bigint not null,        primary key (rid)    )Hibernate:     alter table articles         add constraint FKj05wy4m9xv8nqjnscbno7i2v5         foreign key (authorid)         references peoples (pid)Hibernate:     alter table questions         add constraint FKfnjmh8itrc1ri408e9u8nij8x         foreign key (aid)         references articles (aid)Hibernate:     alter table replies         add constraint FK8api2vr7qnl449l6t4cy75k1x         foreign key (rid)         references articles (aid)

从这里可以看出两个派生类的外键(引用基类主键)的名字是不同,使用@PrimaryKeyJoinColumn(name="rid")就可以自定义字类的外键名,否则默认外键名和父类的主键是一样的···

这里写图片描述 "question" "reply" articles questions replies

Mixing inheritance strategies 混合继承策略

这种方式,就是将前两种方式结合起来使用。先上图(当然不是我画的):

"secondary"

相当于,在第一种情况下,将一个子类抽取出来,放到第二个表中…

@Entity@Inheritance(strategy = InheritanceType.SINGLE_TABLE)@Table(name="articles")@DiscriminatorColumn(name="type")@DiscriminatorValue("article")public class Article {    @Id @Column(name="id")    @GeneratedValue(strategy = GenerationType.IDENTITY)    private Long id;    //发表作者    @JoinColumn(name = "authorid")    @ManyToOne(cascade = CascadeType.REFRESH)    private People author;    //内容    @Lob    private String context;    //发表时间    @Temporal(value= TemporalType.TIMESTAMP)    private Date postTime;
@Entity@DiscriminatorValue(value = "reply")public class Reply extends Article {}
@Entity@DiscriminatorValue("question")@SecondaryTable(name="questions",pkJoinColumns = @PrimaryKeyJoinColumn(name = "qid"))public class Question extends Article {    @Column(table = "questions", nullable = false)    private String title;    public String getTitle() {        return title;    }    public void setTitle(String title) {        this.title = title;    }}
#自动建表Hibernate:     create table articles (        type varchar(31) not null,        id bigint not null auto_increment,        context longtext,        postTime datetime,        authorid bigint,        primary key (id)    )Hibernate:     create table questions (        title varchar(255) not null,        qid bigint not null,        primary key (qid)    )Hibernate:     alter table articles         add constraint FKj05wy4m9xv8nqjnscbno7i2v5         foreign key (authorid)         references peoples (pid)Hibernate:     alter table questions         add constraint FKast1b4f96nx5mjj4efws06nen         foreign key (qid)         references articles (id)
#Article添加2017-04-16 14:48:24,320 INFO  [main] impl.BaseDaoImpl (BaseDaoImpl.java:40) - Save a entity:class community.entity.ArticleHibernate:     insert     into        articles        (authorid, context, postTime, type)     values        (?, ?, ?, 'article')#Question添加2017-04-16 14:48:24,436 INFO  [main] impl.BaseDaoImpl (BaseDaoImpl.java:40) - Save a entity:class community.entity.QuestionHibernate:     insert     into        articles        (authorid, context, postTime, type)     values        (?, ?, ?, 'question')Hibernate:     insert     into        questions        (title, qid)     values        (?, ?)#Reply添加2017-04-16 14:48:24,564 INFO  [main] impl.BaseDaoImpl (BaseDaoImpl.java:40) - Save a entity:class community.entity.ReplyHibernate:     insert     into        articles        (authorid, context, postTime, type)     values        (?, ?, ?, 'reply')
"single" "subbreak" single secondary table

单个表的话,查询时,则只需要查询一个表就可以了,但是,这种方式会浪费空间,表中有许多的空字段..特别是子类基因突变比较的情况下(用继承,可能都会有点鸡肋)…

多个表的话,查询时,可能需要查询多个表的数据,增加查询时间,但是,这种方式很好的体现了面向对象的性质,多态和继承,另一方面也减少了空间的浪费。

第三种方式,则可以说是以上方式的混血儿,一定程度上,减少了空间,个别子类的查询只需要查询一个表就够了。

那就根据具体情况来选择使用哪种策略吧…

0 0