首先說一句,mybatis plus實在太好用了!
mybaits plus的實體類:
以我博客的用戶類作為講解
package com.blog.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableLogic; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import java.io.Serializable; import java.util.Date; /** * * * @author youcong * @email ${email} * @date 2018-04-21 15:27:01 */ @TableName("user") public class UserEntity implements Serializable { private static final long serialVersionUID = 1L; /** * 用戶ID */ @TableId(type=IdType.AUTO) private Integer user_id; /** * 用戶名 */ private String username; /** * 性別 */ private String sex; /** * 電話 */ private String phone; /** * 密碼 */ private String password; /** * 等級 */ private Integer level; /** * 用戶創建時間 */ @TableField(value="create_time") private String createTime; /** * 郵箱 */ private String email; /** * 登錄標識 */ private Integer logo; /** * 設置:用戶ID */ public void setUserId(Integer user_id) { this.user_id = user_id; } /** * 獲取:用戶ID */ public Integer getUserId() { return user_id; } /** * 設置:用戶名 */ public void setUsername(String username) { this.username = username; } /** * 獲取:用戶名 */ public String getUsername() { return username; } /** * 設置:性別 */ public void setSex(String sex) { this.sex = sex; } /** * 獲取:性別 */ public String getSex() { return sex; } /** * 設置:電話 */ public void setPhone(String phone) { this.phone = phone; } /** * 獲取:電話 */ public String getPhone() { return phone; } /** * 設置:密碼 */ public void setPassword(String password) { this.password = password; } /** * 獲取:密碼 */ public String getPassword() { return password; } /** * 設置:等級 */ public void setLevel(Integer level) { this.level = level; } /** * 獲取:等級 */ public Integer getLevel() { return level; } /** * 設置:用戶創建時間 */ public void setCreateTime(String createTime) { this.createTime = createTime; } /** * 獲取:用戶創建時間 */ public String getCreateTime() { return createTime; } /** * 設置:郵箱 */ public void setEmail(String email) { this.email = email; } /** * 獲取:郵箱 */ public String getEmail() { return email; } /** * 設置:登錄標識 */ public void setLogo(Integer logo) { this.logo = logo; } /** * 獲取:登錄標識 */ public Integer getLogo() { return logo; } }
上述的注解什么意思,為什么用,我在第一篇MP實戰中提過也加以描述說過。不過,今天我還是要強調一下,@TableName該注解用英文翻譯就是"表名"的意思,通常在這里面寫實體對應的表名,方便映射。大家還記得hibernate嗎?hibernate中有個配置文件叫:hibernater-cfg.xml,該配置文件主要配置hibernate的數據源和實體映射掃描等等,這個實體映射掃描,就是通過注解,之前是每個實體對應的xml文件,而在這個xml文件中配置實體對應表的屬性。后來hibernate進行升級了,如果是每一個實體對應一個xml文件,隨着項目越來越大,xml文件管理起來也是個問題,於是注解,應需而生。
大家可以參考我的關於spring+hibernate+springmvc框架搭建的例子,看其中有一個實體就是通過注解的形式映射。這個與mybatis plus實體注解也是一個意思,並無多大差異。下面貼個代碼方便講解:
package com.ssh.entity; import lombok.Data; import javax.persistence.*; /** * Created by XRog * On 2/2/2017.2:03 PM */ @Data @Entity @Table(name = "Person") public class Person { @Id @GeneratedValue private Long id; @Column(name = "created") private Long created = System.currentTimeMillis(); @Column(name = "username") private String username; @Column(name = "address") private String address; @Column(name = "phone") private String phone; @Column(name = "remark") private String remark; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public Long getCreated() { return created; } public void setCreated(Long created) { this.created = created; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } }
這是hibernate的實體注解, @Data : 注解在類上, 為類提供讀寫屬性, 此外還提供了 equals()、hashCode()、toString() 方法
@Entity 對實體注釋。任何Hibernate映射對象都要有這個注釋
@Table 的意思與mybatis plus中的@TableName意思是一樣的
@Id和@GeneratedValue是對主鍵的標識,這里與mybatis plus中的@TableId意思也是一樣的
@Column 意思就如其名,標識列的,在屬性上打上該注解,使其與數據表中的字段名進行映射,而mybatis plus這里的@TableField雖有映射的意思,但是還有其他的意思,
比如mybatis中,為什么要用resultType?為什么要用resultMap?原因很簡單,一句話即可解釋,當實體屬性與表的字段名一致時,自動映射,當不一致時,需手動映射。
@TableFiled在此就有這個作用
@TableName的源碼如下:
/** * Copyright (c) 2011-2014, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * <p> * 數據庫表相關 * </p> * * @author hubin * @since 2016-01-23 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface TableName { /** * <p> * 實體對應的表名 * </p> */ String value() default ""; /** * <p> * 實體映射結果集 * </p> */ String resultMap() default ""; }
這里對@Retention和@Target做簡單的說明:
元數據
也叫元注解,是放在被定義的一個注解類的前面 ,是對注解一種限制。
談下這兩個: @Retention 和 @Target
@Retention :用來說明該注解類的生命周期。它有以下三個參數:
RetentionPolicy.SOURCE : 注解只保留在源文件中
RetentionPolicy.CLASS : 注解保留在class文件中,在加載到JVM虛擬機時丟棄
RetentionPolicy.RUNTIME : 注解保留在程序運行期間,此時可以通過反射獲得定義在某個類上的所有注解。
@Target : 用來說明該注解可以被聲明在那些元素之前。
ElementType.TYPE:說明該注解只能被聲明在一個類前。
ElementType.FIELD:說明該注解只能被聲明在一個類的字段前。
ElementType.METHOD:說明該注解只能被聲明在一個類的方法前。
ElementType.PARAMETER:說明該注解只能被聲明在一個方法參數前。
ElementType.CONSTRUCTOR:說明該注解只能聲明在一個類的構造方法前。
ElementType.LOCAL_VARIABLE:說明該注解只能聲明在一個局部變量前。
ElementType.ANNOTATION_TYPE:說明該注解只能聲明在一個注解類型前。
ElementType.PACKAGE:說明該注解只能聲明在一個包名前。
@TableId源碼:
/** * Copyright (c) 2011-2014, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.baomidou.mybatisplus.enums.IdType; /** * <p> * 表主鍵標識 * </p> * * @author hubin * @since 2016-01-23 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface TableId { /** * <p> * 字段值(駝峰命名方式,該值可無) * </p> */ String value() default ""; /** * <p> * 主鍵ID * </p> * {@link IdType} */ IdType type() default IdType.NONE; }
@TableId中有這么幾個屬性,其中用的比較多的就是屬Type
Type常用的枚舉有:
AUTO 主鍵自增
ID_WORKER
INPUT 主鍵以輸入的方式
NONE 默認一般是自增
UUID UUID方式
我個人用的比較多,一個是AUTO,另外一個是UUID,這兩個能滿足大多數的項目需求
@TableFied源碼:
/** * Copyright (c) 2011-2014, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import com.baomidou.mybatisplus.enums.FieldFill; import com.baomidou.mybatisplus.enums.FieldStrategy; /** * <p> * 表字段標識 * </p> * * @author hubin sjy tantan * @since 2016-09-09 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface TableField { /** * <p> * 字段值(駝峰命名方式,該值可無) * </p> */ String value() default ""; /** * <p> * 當該Field為類對象時, 可使用#{對象.屬性}來映射到數據表. * </p> * <p> * 支持:@TableField(el = "role, jdbcType=BIGINT)<br> * 支持:@TableField(el = "role, typeHandler=com.baomidou.xx.typehandler.PhoneTypeHandler") * </p> */ String el() default ""; /** * <p> * 是否為數據庫表字段 * </p> * <p> * 默認 true 存在,false 不存在 * </p> */ boolean exist() default true; /** * <p> * 字段驗證策略 * </p> * <p> * 默認 非 null 判斷 * </p> */ FieldStrategy strategy() default FieldStrategy.NOT_NULL; /** * <p> * 字段自動填充策略 * </p> */ FieldFill fill() default FieldFill.DEFAULT; }
@TableField是比較常用的注解,有的時候覺得ajax要傳實體(這個實體包含其它實體類屬性),通常規范的做法是寫個dto,直接傳輸,一來復用方便,二來簡潔清楚,我們開發中通常不推薦一個實體中嵌入其他實體的屬性,但是有的時候,人有點懶,需求有點變態,為了加快速度,就直接在一個實體中,寫其他實體屬性。
這就好比,在一個html頁面中,建議寫外部js和css,一來規范,二來方便管理,三來復用,不過規范通常是讓人痛苦的,不過對於時常變更的項目需求而言是快樂的,因為代碼規范不亂,但是對於小公司而言,有的時候為了加快項目進度,不管三七二十一,行內樣子能解決,絕對不用外部,最后一個頁面內置一大堆css,js,而且html標簽中又嵌入一大堆css標簽或者js函數等,等到要優化時,有種想罵人的沖動。
題外話就不多說了,總而言之,規范開發雖然是痛苦,但是對於未來是很有益的,堅持規范,做一個代碼潔癖的人!目前我還是不符合。至少我還是與前者所說的,占了一半。深刻的體會到,代碼不規范,亂七八糟帶來的影響。@TableField中的exist屬性就是為了當你的實體包含其它實體時,可以指定它,默認為true,需要指定為false,true的意思是該字段在數據表中存在,false是不存在,通常的話,如果你的自動生成查,查所有,而不使用setSqlSelect()方法指定具體的字段時,如果你的實體中包含其它屬性,但又沒有使用exist時,會出現找不到列異常。避免該異常的方法就是指定exist為false,不過開發過程中,不管怎么樣建議使用setSqlSelect()方法,因為sql優化。調用該方法指明需要字段就是進行最簡單的sql優化。一個個簡單的sql優化,對於一個系統還是很有威力的。
當然使用@TableField的場景是當你的實體屬性與數據表不一致時,進行手動映射,如果一致,就會自動映射。