mybatis和ORM框架相比最大的一个优点就是可以自己编写sql,并且引入了动态sql的概念。上节课我们研究了一下mybatis的环境,他们通过映射文件mapper.xml来执行sql,那么mapper映射文件里面还有很多内容需要我们研究,这节课我们就来研究一下mapper映射文件的内容和动态sql。
1、映射文件里有哪些标签?
映射文件里,我们首先接触到的是mapper标签,这个标签指定了一个映射,在这个标签里面有个属性namespace,这个属性指定一个映射接口,这样映射文件就可以通过映射接口的方法完成映射了。
UserMapper.java(映射接口)
package com.mybatis.mapper;
public interface UserMapper {
public void findIdcard();
}
UserMapper.xml(映射文件)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper">
</mapper>
在mapper标签里面,我们可以写一种处理,sql处理标签有insert、delete、update、select分别处理增删改查,在这四个标签中可以写sql语句。
在mapper标签中,除了增删改查,还可以使用sql标签定义重用的sql语句,如下代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper">
<insert id="add1">
<include refid="addsql">
<property name="name" value="caixiaobai"/>
<property name="age" value="18"/>
<property name="address" value="Beijing"/>
<property name="orderid" value="1"/>
</include>
</insert>
<insert id="add2">
<include refid="addsql">
<property name="name" value="xiaobai"/>
<property name="age" value="18"/>
<property name="address" value="Beijing Chaoyang"/>
<property name="orderid" value="1"/>
</include>
</insert>
<sql id="addsql">
INSERT INTO user(name,age,address,orderid) VALUES('${name}',${age},'${address}',${orderid})
</sql>
</mapper>
在add1中和add2中,都使用了共同的sql语句,不过添加的参数不同。使用上面的映射文件,可以将重用的sql语句提取到sql标签中,并使用property标签对sql语句进行传参。
2、如何向sql中传入参数?
如果我们在sql中需要一些参数,该如何从程序中动态获取呢?我们通常在mapper映射文件的insert、delete、update、select标签中添加parameterType属性,属性值是我们需要传参的类型。我们的代码不在累述mybatis-config配置文件,传参的mybatis代码如下
UserMapper.java
package com.mybatis.mapper;
public interface UserMapper {
public void addUser(String name);
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper">
<insert id="addUser" parameterType="String">
INSERT INTO user(name,age,address,orderid) VALUES(#{name},18,'Beijing',1);
</insert>
</mapper>
MybatisTest.java
package com.mybatis.test;
import java.io.IOException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MybatisTest {
public static void main(String[] args) throws IOException {
// 获取sqlSession
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
sqlSession.insert("com.mybatis.mapper.UserMapper.addUser","caixiaobai");
sqlSession.commit();
sqlSession.close();
}
}
上面我们演示了一个传参简单类型的情况,传参list或者set集合也是这样,我们在mapper映射文件中使用#{name}占位符来代表参数name的值。如果传递的是自定义的类型,则使用#{name}占位符来代表参数中name属性的值。如果传参是map集合,则使用#{name}占位符来代表参数中name键的值。
3、如果sql中需要返回一些值该怎么操作?
刚才我们讲到传参在insert、delete、update、select标签中加入parameterType属性,如果我们想获取到sql的结果或者结果集,我们使用resultType属性,但是这个属性只有select标签有。我们来看一下如何获取到user表里所有的数据吧。
User.java
package com.mybatis.pojo;
/**
* 就是一个简单的pojo,不需要继承任何类或者接口
* 这就是mybatis为什么被称为低侵入式
*
*/
public class User {
private String name;
private int age;
private String address;
private int orderid;
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
UserMapper.java
package com.mybatis.mapper;
import java.util.List;
import com.mybatis.pojo.User;
public interface UserMapper {
public List<User> findUser();
}
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper">
<select id="findUser" resultType="User">
SELECT * FROM user;
</select>
</mapper>
MybatisTest.java
package com.mybatis.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.mybatis.pojo.User;
public class MybatisTest {
public static void main(String[] args) throws IOException {
// 获取sqlSession
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
List<Object> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.findUser");
for (Object user : list) {
System.out.println(((User)user).getName());
}
sqlSession.commit();
sqlSession.close();
}
}
这样,mybatis会自动将获取到列表的响应字段赋值到pojo的相应属性上,我们就可以获取到sql查找的所有用户了。但是很多时候,我们数据库中的字段名称和pojo的属性名称不统一,这时候我们使用resultType就没办法自动匹配了,需要我们借助resultMap属性,看代码:
User.java
package com.mybatis.pojo;
/**
* 就是一个简单的pojo,不需要继承任何类或者接口
* 这就是mybatis为什么被称为低侵入式
*
*/
public class User {
private String userName;
private int age;
private String address;
private int orderid;
public int getOrderid() {
return orderid;
}
public void setOrderid(int orderid) {
this.orderid = orderid;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
UserMapper.java
package com.mybatis.mapper;
import java.util.List;
import com.mybatis.pojo.User;
public interface UserMapper {
public List<User> findUser();
}
UserMapper.java
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.UserMapper">
<select id="findUser" resultMap="userMap">
SELECT * FROM user;
</select>
<resultMap type="User" id="userMap">
<!-- property指定对象的属性名,colum指定字段名 -->
<result property="userName" column="name"/>
<!-- 其余的属性没有手动匹配,会按照字段名和属性名自动匹配 -->
</resultMap>
</mapper>
MybaitsTest.java
package com.mybatis.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.mybatis.pojo.User;
public class MybatisTest {
public static void main(String[] args) throws IOException {
// 获取sqlSession
SqlSession sqlSession = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml")).openSession();
List<Object> list = sqlSession.selectList("com.mybatis.mapper.UserMapper.findUser");
for (Object user : list) {
System.out.println(((User)user).getUserName());
}
sqlSession.commit();
sqlSession.close();
}
}
我们在映射文件里使用resultMap代替了resultType引入一个resultMap标签,这个标签里的type指定返回的类型或者返回集合里的类型,再使用result标签将字段名和属性名进行匹配。
4、映射文件中的${}和#{}有什么区别?
#{}是占位符,类似sql语句中的“?”,可以防止注入。
${}是变量引用,比如我们上节课提到的外部数据源的引入。