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。