mybatis基礎系列(二)——基礎語法、別名、輸入映射、輸出映射

增刪改查

mapper根節點及其子節點

mybatis框架須要讀取映射文件建立會話工廠,映射文件是以<mapper>做爲根節點,在根節點中支持9個元素,分別爲insert、update、delete、select(增刪改查);cache、cache-ref、resultMap、parameterMap、sql。以下圖:java

image

命名空間

<mapper>根節點有個屬性namespace,做用是對sql語句進行分類化管理。mysql

select節點

佔位符#{}

一個<select>表明一條查詢語句,<select>經常使用屬性有id,parameterType,resultType。<select>節點的內容爲sql語句,其語法與日常寫的sql語句類似,不一樣的地方是條件參數能夠經過佔位符#{}替換。例如:spring

sql語法:sql

SELECT * FROM t_emp WHERE empno=7369

mybitis中的語法:數據庫

SELECT * FROM t_emp WHERE empno=#{empno}

id:標誌映射文件中的sql,一般id也稱爲statement的id。id的值就是xxxMapper.java中的方法名。apache

parameterType:執行sql語句中的輸入參數的類型。springboot

resultType:指定sql輸出結果映射成java類型的對象。mybatis

#{}:表示一個佔位符app

#{id}:其中id表示接收輸入的參數,參數名稱就是id。#{}中的參數能夠是任意對象。框架

示例與運行問題

EmpMapper.xml

<mapper namespace="com.itpsc.mapper.EmpMapper" >

<select id="queryById" parameterType="int" resultType="com.itpsc.entity.Emp">
  SELECT * FROM t_emp WHERE empno=#{empno}
</select>

</mapper>


//EmpMapper.java
public interface EmpMapper extends BaseMapper<Emp> {
    Emp queryById(Integer empno);
}

//EmpService.java
public interface EmpService {
    Emp queryById(Integer empno);
}

//EmpServiceImpl.java
@Service
public class EmpServiceImpl extends ServiceImpl<EmpMapper,Emp> implements EmpService {

    public EmpServiceImpl() {
        super();
    };
    public EmpServiceImpl(EmpMapper mapper) {
        this.baseMapper = mapper;
    };
    @Override
    public Emp queryById(Integer empno) {
        return this.baseMapper.queryById(empno);
    }
}

//EmpTests.java
@RunWith(SpringRunner.class)
@SpringBootTest
public class EmpTests {
    @Resource
    private EmpService empService;
    @Test
    public void contextLoads() {
    }
    @Test
    public void testQueryById() {
        System.out.println(empService.queryById(7369));
    }
}

運行報錯:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.itpsc.mapper.EmpMapper.queryById

找不到xml,發如今idea編譯後的classes路徑下並無相應的XML文件。

image

由於IDEA在編譯的時候忽略掉了XML文件,一個解決方法是將全部的XML文件移動到Resource文件夾下,這樣在編譯的時候就會將XML文件一塊兒。

另外一個方法是配置Maven不過濾src/main/java目錄下的.properties文件和.xml文件。

<resources>
    <resource>
        <directory>src/main/java</directory>
        <includes>
            <include>**/*.properties</include>
            <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
    </resource>
</resources>

再次編譯就看到了classes目錄下有xml文件了。

image

運行test後輸出:

Emp{empno=7369, ename='SMITH', job='CLERK', mgr=7902, hiredate=Wed Dec 17 00:00:00 CST 1980, sal=800.0, comm=null, deptno=20}

拼接${}

${}:用來拼接sql字符串,將接收到的參數內容不加任何修飾拼接在sql語句中。

sql語法:

SELECT * FROM t_emp WHERE ename LIKE 'SMITH';

mybitis中的語法:

<select id="queryLikeName" parameterType="String" resultType="com.itpsc.entity.Emp">
  SELECT * FROM t_emp WHERE ename LIKE '${_parameter}'
</select>

注意

若是傳入的參數類型爲String類型,則參數名需統一修改成_parameter,不能將參數設爲bean裏的名稱。

不然運行報錯爲:There is no getter for property named 'preCode' in 'class java.lang.String


insert節點

一個<insert>表明一條insert語句,和<select>節點同樣,<insert>其語法與日常寫的sql語句類似,不一樣的地方是條件參數能夠經過佔位符#{}替換。

sql語法:

insert into t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(7100,’itpsc’,’developer’,7902,’1980-12-10’,1000.00,200.00,20)

mybitis中的語法:

<insert id="add" parameterType="com.itpsc.entity.Emp">
    insert into t_emp(empno,ename,job,mgr,hiredate,sal,comm,deptno)
    values(#{empno},#{ename},#{job},#{mgr},#{hiredate,jdbcType=DATE},#{sal},#{comm},#{deptno})
  </insert>

注意日期類型

mybatis日期類型的字段,要加jdbcType=DATE。不然會報錯:There is no getter for property named 'hirdate' in 'class com.itpsc.entity.Emp'。

Mybatis中javaType和jdbcType對應關係

JDBC Type           Java Type  
CHAR                String  
VARCHAR             String  
LONGVARCHAR         String  
NUMERIC             java.math.BigDecimal  
DECIMAL             java.math.BigDecimal  
BIT             boolean  
BOOLEAN             boolean  
TINYINT             byte  
SMALLINT            short  
INTEGER             int  
BIGINT              long  
REAL                float  
FLOAT               double  
DOUBLE              double  
BINARY              byte[]  
VARBINARY           byte[]  
LONGVARBINARY               byte[]  
DATE                java.sql.Date  
TIME                java.sql.Time  
TIMESTAMP           java.sql.Timestamp  
CLOB                Clob  
BLOB                Blob  
ARRAY               Array  
DISTINCT            mapping of underlying type  
STRUCT              Struct  
REF                         Ref  
DATALINK            java.net.URL

insert與非自增主鍵返回

有時候新增記錄以後,須要這條新增記錄的主鍵,以便業務使用,可是新增以後再將其查詢出來明顯不合理,效率也變低了。mybatis能夠將insert的記錄的主鍵返回。使用mysql的uuid()函數生成主鍵,須要修改表中id字段類型爲string,長度設置成35位。

mybatis的<selectKey>能夠幫咱們實現。Insert以前先經過uuid()查詢到主鍵,將主鍵輸入到sql語句中。

UserMapper.xml

<mapper namespace="com.itpsc.mapper.UserMapper" >
    <insert id="adduser" parameterType="com.itpsc.entity.User">
        <selectKey keyProperty="id" order="BEFORE" resultType="java.lang.String">
            SELECT uuid()
        </selectKey>
        insert into t_user(id,name,password,phone) values(#{id},#{name},#{password},#{phone})
    </insert>
</mapper>
測試
@Test
public void testAddUser() {
    User user = new User();
    //user.setId(1L);
    user.setName("uuid name1");
    user.setPassword("98764");
    user.setPhone("13877711111");
    System.out.println(userService.adduser(user));
    System.out.println(user.getId());
}

輸出:

1
9a64919e-b02f-11e8-8b1f-f48e38ec6bad

insert與自增主鍵返回

再將user表中的id字段修改成Bigint類型,並設爲自增。User.java中id修改成Long類型。經過mysql函數LAST_INSERT_ID()獲取到剛插入記錄的自增主鍵,是insert以後調用此函數。

<insert id="getIdAfterAdduser" parameterType="com.itpsc.entity.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into t_user(name,password,phone) values(#{name},#{password},#{phone})
</insert>
@Test
public void getIdAfterAdduser() {
    User user = new User();
    user.setName("auto add id");
    user.setPassword("98764");
    user.setPhone("13877711111");
    System.out.println(userService.getIdAfterAdduser(user));
    System.out.println(user.getId());
}

運行輸出:
1
3

delete節點

sql語法:

delete FROM t_user WHERE id=3

mybitis中的語法:

delete FROM t_user WHERE id=#{id}

<delete id="delete" parameterType="java.lang.Long">
        DELETE from t_user WHERE id=#{id}
</delete>


update節點

<update id="updateById" parameterType="com.itpsc.entity.User">
        UPDATE t_user set NAME=#{name},password=#{password},phone=#{phone} WHERE id=#{id}
</update>

把整個java對象傳入,要更新哪些字段sql語句決定。


佔位符與拼接符小結

#{}表示一個佔位符號,#{}接收輸入參數,類型能夠是簡單類型也能夠是複雜的數據類型。#{}接收對象值,經過OGNL語法(user.username)讀取對象中的屬性值。

${}表示一個拼接符號,會引用sql注入,不建議使用${}。${}接收輸入參數,類型能夠是簡單類型也能夠是複雜數據類型。${}接收對象值,經過OGNL語法(user.username)讀取對象中的屬性值。

出入參定義別名

批量定義別名

在mapper.xml中,定義不少的statement,statement須要parameterType指定輸入參數的類型、須要resultType指定輸出結果的映射類型。

若是在指定類型時輸入類型全路徑,不方便進行開發,能夠針對parameterType或resultType指定的類型定義一些別名,在mapper.xml中經過別名定義,方便開發。

在springboot 的yml配置文件中經過type-aliases-package定義別名,在對parameterType或resultType指定的類型中就能夠省略包名。

mybatis-plus:
   mapper-locations: "classpath:com/itpsc/mapper/**/*.xml"
   type-aliases-package: "com.itpsc.entity"
   global-config:
      db-column-underline: true

<insert id="adduser" parameterType="User">
    insert into t_user(name,password,phone) values(#{name},#{password},#{phone})
</insert>

輸入映射

parameterType


前面咱們學習的輸入都是簡單對象,若是輸入參數的類型是複雜對象(包裝對象),該怎麼寫呢。

<select id="queryList" parameterType="com.itpsc.request.EmpRequest" resultType="com.itpsc.vo.EmpVo">
    SELECT * FROM t_emp WHERE deptno=#{emp.deptno} and job=#{emp.job}
  </select>
public interface EmpMapper extends BaseMapper<Emp> {
//...
    EmpVo queryList(EmpRequest request);
}

public class EmpRequest{
    private Emp emp;
    //其它條件
    public Emp getEmp() {
        return emp;
    }
    public void setEmp(Emp emp) {
        this.emp = emp;
    }
}


public class EmpVo extends Emp{
//...
}

使用parameterType進行輸入映射,類型是包裝對象,可是佔位符裏用的是被包裝對象的屬性。經過#{emp.deptno}取出被包裝對象的deptno屬性。


輸出映射

resultType

運行測試方法報錯:

org.mybatis.spring.MyBatisSystemException:
 nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

返回數據類型由xxxMapper.java接口中聲明的方法的返回類型和xxxMapper.xml文件共同決定。若是mapper方法返回單個對象(非集合對象),代理對象內部經過selectOne查詢數據庫。若是mapper方法返回集合對象,代理對象內部經過selectList查詢數據庫。不管是返回單一對象仍是對象列表,xxxMapper.xml中的配置都是同樣的,都是resultMap=」***Map」或resultType=「* .* .*」類型。

例如:

返回單個對象resultType的值爲"com.itpsc.entity.Emp"

返回多個對象resultType的值也是"com.itpsc.entity.Emp"

因此將mapper方法的返回類型聲明爲List<Emp>便可。

使用resultType進行輸出映射,只有查詢出來的列名和對象中的屬性名一致,該列才能夠映射成功。若是查詢出來的列名和對象中的屬性名所有不一致,沒有建立對象。只要查詢出來的列名和對象中的屬性有一個一致,就會建立對象。

若是咱們把上面例子中的EmpVo 不繼承Emp,查詢出來就不建立對象。以下圖

image

image


resultMap

若是查詢出來的列名和對象的屬性名不一致,經過定義一個resultMap對列名和對象屬性名之間做一個映射關係。

一、定義resultMap

二、使用resultMap做爲statement的輸出映射類型


<resultMap id="userMap" type="com.itpsc.entity.Emp" >
    <result column="_empno" property="empnum" jdbcType="INTEGER" />
    <result column="_ename" property="ename" jdbcType="VARCHAR" />
    <result column="_job" property="job" jdbcType="VARCHAR" />
    <result column="_mgr" property="mgr" jdbcType="INTEGER" />
    <result column="_hiredate" property="hiredate" jdbcType="DATE" />
    <result column="_sal" property="sal" jdbcType="REAL" />
    <result column="_comm" property="comm" jdbcType="REAL" />
    <result column="_deptno" property="deptno" jdbcType="INTEGER" />
  </resultMap>

  <select id="queryById" parameterType="int"resultMap ="userMap">
    SELECT empno _empno,ename _ename,job _job,mgr _mgr,hiredate _hiredate,sal _sal,comm _comm,deptno _deptno FROM t_emp WHERE empno=#{empno}
  </select>

本篇到此結束,下篇預告mybatis基礎系列(三)——動態sql。

相關文章
相關標籤/搜索