MyBatis: CRUD

张天宇 on 2020-03-21

MyBatis中的基于代理Dao的CRUD,参数深入和结果集的深入。

CRUD

查询所有

findAll()声明

1
2
3
public interface IUserDao {
List<User> findAll();
}

配置IUserDao.xml映射文件

1
2
3
4
5
6
7
8
9
<?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="top.tyzhang.dao.IUserDao">
<select id="findAll" resultType="top.tyzhang.domain.User">
select * from userm
</select>
</mapper>

使用

1
2
3
4
5
6
7
8
9
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
SqlSession session=factory.openSession();
IUserDao userDao=session.getMapper(IUserDao.class);
List<User> users = userDao.findAll();
for (User user:users)
System.out.println(user);
session.close();
in.close();

保存操作

1
void saveUser(User user);

配置映射文件,注意表达式中的属性要和类中属性一致

1
2
3
<insert id="saveUser" parameterType="top.tyzhang.domain.User">
insert into userm(username, address, sex, birthday) values(#{username}, #{address}, #{sex}, #{birthday})
</insert>

测试类,使用junit进行了代码整合抽取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MyBatisTest {
private InputStream in;
private IUserDao userDao;
private SqlSession session;

@Before
public void init() throws IOException {
in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
session=factory.openSession();
userDao=session.getMapper(IUserDao.class);
}

@After
public void destroy() throws IOException {
//因为默认关闭自动提交事务,所以打开提交事务
session.commit();
session.close();
in.close();
}

@Test
public void findAll() throws IOException {
List<User> users = userDao.findAll();
for (User user:users)
System.out.println(user);
}
@Test
public void testSave() throws IOException {
User user = new User();
user.setUsername("ztygalay");
user.setAddress("shandong");
user.setSex("男");
user.setBirthday(new Date());
userDao.saveUser(user);
}
}
新增用户ID的返回值
1
2
3
4
5
6
7
<insert id="saveUser" parameterType="top.tyzhang.domain.User">
<!--实体类属性,数据库属性,返回类型,执行顺序-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id()
</selectKey>
insert into userm(username, address, sex, birthday) values(#{username}, #{address}, #{sex}, #{birthday})
</insert>
1
2
3
4
5
6
7
8
User user = new User();
user.setUsername("ztygalay");
user.setAddress("shandong");
user.setSex("男");
user.setBirthday(new Date());
userDao.saveUser(user);
System.out.println(user);
//输出:User{id=56, username='ztygalay', address='shandong', sex='男', birthday=Thu Mar 19 14:41:03 CST 2020}

更新操作

1
void updateUser(User user);
1
2
3
<update id="updateUser" parameterType="top.tyzhang.domain.User">
update userm set username=#{username}, address=#{address}, sex=#{sex}, birthday=#{birthday} where id=#{id}
</update>
1
2
3
4
5
6
7
8
9
10
@Test
public void testUpdate() throws IOException {
User user = new User();
user.setId(55);
user.setUsername("张天宇");
user.setAddress("山东");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}

删除操作

1
void deleteUser(Integer id);
1
2
3
4
<delete id="deleteUser" parameterType="Integer">
<!--参数只有一个,参数给一个占位符就可以,即只有一个参数时随意写-->
delete from userm where id = #{id}
</delete>
1
2
3
4
@Test
public void testDelete(){
userDao.deleteUser(55);
}

查询一个

1
User findById(Integer id);
1
2
3
<select id="findById" parameterType="Integer" resultType="top.tyzhang.domain.User">
select * from userm where id = #{id}
</select>
1
2
3
4
@Test
public void testFindOne(){
System.out.println(userDao.findById(48));
}

模糊查询

1
List<User> findByName(String username);
1
2
3
4
5
<!--模糊查询的百分号操作由函数提供-->
<select id="findByName" parameterType="String" resultType="top.tyzhang.domain.User">
select * from userm where username like #{name}
<!--select * from userm where username like '%${value}%' 其中value是固定名称,了解不推荐-->
</select>
1
2
3
4
5
6
@Test
public void testFindName(){
List<User> users=userDao.findByName("%王%");
for (User user:users)
System.out.println(user);
}

使用value法时,SQL执行的语句为select * from userm where username like '%王%',即字符串的拼接。而使用name法时,SQL执行的语句为select * from userm where username like ?,参数为%王%(String),即使用的PreparedStatement的参数占位符,更好一些。

查询总数

1
int findTotal();
1
2
3
<select id="findTotal" resultType="int">
select count(id) from userm
</select>

参数深入

parameterType(输入类型)

  • 传递简单类型

  • 传递pojo对象

    使用orgl表达式解析对象字段的值,#{}或${}括号中的值为pojo属性名称,上述即为示例。

  • 传递pojo包装对象,利用一个对象的多个属性查询单个或多个对象。

    创建接口

    1
    List<User> findUserByVo(QueryVo vo);

    创建QueryVo实体对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class QueryVo {
    private User user;
    public User getUser() {
    return user;
    }
    public void setUser(User user) {
    this.user = user;
    }
    }

    配置xml

    1
    2
    3
    4
    <select id="findUserByVo" parameterType="top.tyzhang.domain.QueryVo" resultType="top.tyzhang.domain.User">
    <!--使用QueryVo中的user的username属性-->
    select * from userm where username like #{user.username}
    </select>

    测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Test
    public void testFindVo(){
    QueryVo vo =new QueryVo();
    User user=new User();
    user.setUsername("%王%");
    vo.setUser(user);
    List<User> users=userDao.findUserByVo(vo);
    for (User userq:users)
    System.out.println(userq);
    }

OGNL表达式: Object Graphic Navigation Language,对象图导航语言。它是通过对象的取值方法来获取数据,在写法上把get省略了。

resultType(输出类型)

对输出结果进行封装,基本类型、pojo对象、pojo列表。

解决数据库列名和实体类属性不一致

  1. 起别名

    1
    2
    3
    4
    5
     <!--配置查询所有  其中id不能乱写必须是dao接口中的方法  resultType写的是实体类的全路径-->
    <select id="findAll" resultType="top.tyzhang.domain.User">
    <!--实体类中的属性名和数据库表中元素名字匹配不上时,使用别名即可匹配。id为数据库中表的列名,userId为实体类中属性名-->
    select id as userId,username as userName,address as userAddress ,sex as userSex, birthday as userBirthday from user
    </select>
  2. 配置查询结果中的列名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!--配置查询结果的列名和实体类的属性名的对应关系-->
    <resultMap id="userMap" type="top.tyzhang.domain.User">
    <!--主键字段的对应-->
    <id property="userId" column="id"></id>
    <!--非主键字段的对应-->
    <result property="userName" column="username"></result>
    <result property="userAddress" column="address"></result>
    <result property="userSex" column="sex"></result>
    <result property="userBirthday" column="bithday"></result>
    </resultMap>
    <!--再在查询的sql语句的xml中加入配置-->
    <select id="findAll" resultMap="userMap">
    select * from user
    </select>

XML中的一些配置

1. 使用properties配置数据库连接信息

  • URL属性
    • URL:Uniform Resource Locator,统一资源定位符,可以唯一标志一个资源的位置。如,http://localhost:8080/mybatisserver/demo1Servlet。

    • URI:Uniform Resource Identifier,统一资源标识符,是在应用中可以可以唯一标志一个资源的位置。

    • 精准性:URL>URI

    • <properties url="file:///C:/Users/ty/tytyty/src/main/resources/jdbcConfig.properties">
      </properties>
      
      1
      2
      3
      4
      5
      6
      7
        
      - `resources`属性

      - 用于指定配置文件的位置,是按照类路径来写的,必须存在于类路径下。

      - ```xml
      <properties resource="jdbcConfig.properties"></properties>

2. 使用typeAliases配置别名

1
2
3
4
5
<!--使用typeAliases配置别名,他只能配置domain中类的别名-->
<typeAliases>
<!--typeAlias用于配置别名,type属性指定的是实体类中的全限定类名。alias属性指定别名,当指定了别名后不在区分大小写-->
<typeAlias type="top.tyzhang.domain.User" alias="user"></typeAlias>
</typeAliases>

3. 使用package配置别名

1
2
3
4
<typeAliases>
<!--用于指定要配置别名的包,当指定后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="top.tyzhang.domain"/>
</typeAliases>

配置映射文件位置中也有package标签。

1
2
3
4
5
<mappers>
<!-- <mapper resource="top/tyzhang/dao/IUserDao.xml"/>-->
<!--package标签是用于指定dao接口所在的包,当指定了之后就不需要再写mapepr以及resource或者class了-->
<package name="top.tyzhang.dao"/>
</mappers>