mybatis框架須要讀取映射文件建立會話工廠,映射文件是以<mapper>做爲根節點,在根節點中支持9個元素,分別爲insert、update、delete、select(增刪改查);cache、cache-ref、resultMap、parameterMap、sql。以下圖:java
<mapper>根節點有個屬性namespace,做用是對sql語句進行分類化管理。mysql
一個<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文件。
由於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文件了。
運行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語句,和<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
有時候新增記錄以後,須要這條新增記錄的主鍵,以便業務使用,可是新增以後再將其查詢出來明顯不合理,效率也變低了。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
再將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
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 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>
前面咱們學習的輸入都是簡單對象,若是輸入參數的類型是複雜對象(包裝對象),該怎麼寫呢。
<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屬性。
運行測試方法報錯:
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,查詢出來就不建立對象。以下圖
若是查詢出來的列名和對象的屬性名不一致,經過定義一個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。