1、查询
1.1 查询表全部数据
- UserMapper:接口类
public interface UserMapper {
// 查询User表全部信息
public List<User> findAll();
}
- 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.lyj.com.lyj.mapper.UserMapper">
<!-- 配置查询所有用户 -->
<select id="findAll" resultType="com.lyj.com.lyj.domain.User">
SELECT * FROM user
</select>
</mapper>
- 测试类:
public class MyTest {
private InputStream is;
private SqlSession sqlSession;
private UserMapper mapper;
/**
* 测试之前执行,用于初始化
*/
@Before
public void init() throws Exception {
// 1. 读取配置文件
is = Resources.getResourceAsStream("mybatis-config.xml");
// 2. 创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 3. 获取SqlSession对象
sqlSession = factory.openSession();
// 4. 使用SqlSession创建Mapper的代理对象
mapper = sqlSession.getMapper(UserMapper.class);
}
/**
* 测试结束执行,用于提交事务和释放资源
*/
@After
public void destroy() throws Exception {
// 提交事务,提交后数据库才能更新,否则会回滚
sqlSession.commit();
// 释放资源
sqlSession.close();
is.close();
}
/**
* 测试查询全部用户信息
*/
@Test
public void testFindAll() {
List<User> users = mapper.findAll();
for(User user : users){
System.out.println(user);
}
}
}
MyBatis中的事务自动提交设置,需要我们在创建 SqlSession 时传入一个布尔值:
sqlSession = factory.openSession(true);
- 运行结果:
1.2 查询特定数据
- 接口方法:根据id查询表
public User findById(Integer id);
- 接口映射文件配置:配置查询某个用户,当接口方法参数唯一时,sql 语句中的 #{uid} 可与方法参数名称 id 不一致。
<select id="findById" parameterType="java.lang.Integer" resultType="com.lyj.domain.User">
SELECT * FROM user WHERE id = #{uid}
</select>
- 测试方法:
/**
* 测试查询某一用户信息
*/
@Test
public void testFindById() {
User user = mapper.findById(48);
System.out.println(user);
}
- 运行结果:
1.3 模糊查询
- 接口方法:根据用户名查询表
public List<User> findByName(String name);
- 接口映射文件配置:根据用户名模糊查询多个用户
<select id="findByName" parameterType="java.lang.String" resultType="com.lyj.domain.User">
SELECT * FROM user WHERE username LIKE #{name}
</select>
- 测试方法:
/**
* 测试模糊查询
*/
@Test
public void testFindByName() {
// 映射文件中的 SQL 语句并没有对参数进行模糊查询处理,需手动为查询的关键字进行 % 拼接
List<User> users = mapper.findByName("%王%");
users.forEach(System.out::println);
}
- 运行结果:
如果想调用方法查询时,只传入查询的关键字,可以在 sql 语句中进行拼接:
// 调用concat()函数拼接
SELECT * FROM user WHERE username LIKE concat('%',#{name},'%');
// 手动拼接
SELECT * FROM user WHERE username LIKE "%"#{name}"%";
2、添加数据
- 接口方法:添加单个用户数据
public void addUser(User user);
- 接口映射文件配置:
<insert id="addUser" parameterType="com.lyj.domain.User">
INSERT INTO user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>
在添加用户的时候,如果想获取新增数据的自增 id 值,可以使用 <selectKey></selectKey> 标签,id 值在执行完 sql 语句后会存入 user 对象:
<insert id="addUser" parameterType="com.lyj.domain.User">
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
SELECT LAST_INSERT_ID()
</selectKey>
INSERT INTO user(username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
</insert>
- keyProperty:表示 selectKey 语句结果应该被设置的目标属性(对应实体类)。
- keyColumn:表示匹配属性的返回结果集中的列名称(对应数据库结果集);
- order:可以被设置为 BEFORE 或 AFTER,表示在语句之前或之后执行。
- 测试方法:
/**
* 测试添加数据
*/
@Test
public void testAddUser() {
User user = new User();
user.setUsername("小明");
user.setBirthday(new Date());
user.setAddress("上海");
user.setSex("男");
System.out.println("sql执行前:" + user);
mapper.addUser(user);
System.out.println("sql执行后:" + user);
}
- 运行结果:
- 控制台输出(使用<selectKey>标签配置时):
3、更新数据
- 接口方法:
/**
* 更新用户数据
* @param user 要更新的用户数据
* @return 更新成功返回1,失败返回0
*/
public int updateUser(User user);
- 接口映射文件配置:
<update id="updateUser" parameterType="com.lyj.domain.User">
UPDATE user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
</update>
- 测试方法:
/**
* 测试更新数据
*/
@Test
public void testUpdateUser() {
User user = new User();
user.setUsername("小红");
user.setBirthday(new Date());
user.setAddress("广州");
user.setSex("女");
// id 为自己数据库中存在的值
user.setId(49);
int count = mapper.updateUser(user);
System.out.println("更新条数为 : " + count);
}
- 运行结果:
4、删除数据
- 接口方法:
// 根据id删除用户
public int deleteUser(Integer id);
- 接口映射文件配置:
<delete id="deleteUser" parameterType="com.lyj.domain.User">
DELETE FROM user WHERE id = #{uid}
</delete>
- 测试方法:
/**
* 测试删除用户
*/
@Test
public void testDeleteUser(){
int count = mapper.deleteUser(41);
System.out.println("删除条数为 : " + count);
}
- 运行结果:
5、聚合函数
- 接口方法:
// 查询用户总数
int countUser();
- 接口映射文件配置:
<select id="countUser" resultType="int">
SELECT count(id) FROM user
</select>
- 测试方法:
/**
* 测试查询用户总数
*/
@Test
public void testCountUser() {
int count = mapper.countUser();
System.out.println("总记录数为 : " + count);
}
- 运行结果:
6、参数解析
6.1 parameterType
传入参数类型,将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
- OGNL 表达式:
对象导航图语言(Object Graph Navigation Language),OGNL可以让我们用非常简单的表达式访问对象层,例如,当前环境的根对象为 user ,则表达式 user.name 可以让我们访问到 user 的 name 属性。 - POJO 对象:
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
MyBatis 使用 OGNL 表达式解析对象字段的值,#{} 或者 ${} 括号中的值为 pojo 属性名称。
#{} :默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。
${}:使用 ${} 参数语法时,会直接在 SQL 语句中直接插入一个不转义的字符串,即会被直接置换。
6.1.1 传递简单类型
<select id="findById" parameterType="java.lang.Integer" resultType="com.lyj.domain.User">
SELECT * FROM user WHERE id = #{uid}
</select>
6.1.2 传递pojo对象
<update id="updateUser" parameterType="com.lyj.domain.User">
UPDATE user SET username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} WHERE id = #{id}
</update>
6.1.3 传入pojo封装对象
在开发中如果想实现复杂查询 ,查询条件不仅包括用户查询条件,还包括其它的查询条件,这时可以使用 pojo 包装对象传递输入参数。
- QueryVo:vo 类,封装多个查询条件
public class QueryVo implements Serializable {
private User user;
// 其他查询条件
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- 接口层方法:
List<User> findUsersByVo(QueryVo vo);
- 映射文件配置
<select id="findUsersByVo" parameterType="com.lyj.domain.QueryVo" resultType="com.lyj.domain.User">
SELECT * FROM user WHERE username LIKE #{user.username}
</select>
- 测试方法
@Test
public void testFindUsersByVo() {
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");
vo.setUser(user);
List<User> users = mapper.findUsersByVo(vo);
users.forEach(System.out::println);
}
6.2 resultType
结果类型,期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。
6.3 resultMap
结果映射,对外部 resultMap 的命名引用。在实体类的属性和数据库表的列名不一致时,那么查询结果将无法封装进实体类。此时,可以使用 resultMap 来对实体类属性和表列名进行映射,也可以在 SQL 语句中为所有列起别名。
注意,resultType 和 resultMap 之间只能同时使用一个。
- MyUser:与数据库表不对应的实体类
public class MyUser implements Serializable {
private Integer my_id;
private String my_username;
private Date my_birthday;
private String my_sex;
private String my_address;
public Integer getMy_id() {
return my_id;
}
public void setMy_id(Integer my_id) {
this.my_id = my_id;
}
public String getMy_username() {
return my_username;
}
public void setMy_username(String my_username) {
this.my_username = my_username;
}
public Date getMy_birthday() {
return my_birthday;
}
public void setMy_birthday(Date my_birthday) {
this.my_birthday = my_birthday;
}
public String getMy_sex() {
return my_sex;
}
public void setMy_sex(String my_sex) {
this.my_sex = my_sex;
}
public String getMy_address() {
return my_address;
}
public void setMy_address(String my_address) {
this.my_address = my_address;
}
@Override
public String toString() {
return "MyUser{" +
"my_id=" + my_id +
", my_username='" + my_username + '\'' +
", my_birthday=" + my_birthday +
", my_sex='" + my_sex + '\'' +
", my_address='" + my_address + '\'' +
'}';
}
}
- 方法一:在 SQL 语句中为所有列起别名,使别名与实体类属性名一致:
<select id="findMyAll" resultType="com.lyj.domain.MyUser">
SELECT id AS my_id, username AS my_username, birthday AS my_birthday, sex AS my_sex, address AS my_address FROM user
</select>
因为不用解析 xml 文件,故执行效率相对高;在开发时容易产生重复工作,故开发效率较低。
- 方法二:使用 resultMap 完成结果集到实体类的映射。
<!-- 配置 resultMap ,完成实体类与数据库表的映射 -->
<resultMap id="userMap" type="com.lyj.domain.MyUser">
<id property="my_id" column="id" />
<result property="my_username" column="username"/>
<result property="my_birthday" column="birthday"/>
<result property="my_address" column="address"/>
<result property="my_sex" column="sex"/>
</resultMap>
<!-- resultMap:值为上面配置的resultMap的 id -->
<select id="findMyAll" resultMap="userMap">
SELECT * FROM user
</select>
因为要解析 xml 文件,故执行效率相对低;在开发时可以简化工作,故开发效率较高。
参考资料: