Mybatis学习之路 第二篇
- 在第一篇入门案例的基础上,代码框架和结构都不变,我们继续学习,增加新的功能。
- 本文涉及以下内容:
1. 基于xml的Mybatis的CRUD操作
2. Mybatis中实体类和数据库字段不一样的解决方法
3. properties、typeAliases(类型别名)和mapper(映射器)的使用
1. 基于xml的Mybatis的CRUD操作 |
1.1 我们修改IUserDao中的内容如下:
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
/**
* 保存方法
* @param user
*/
void saveUser(User user);
/**
* 更新用户
* @param user
*/
void updateUser(User user);
/**
* 删除用户
* @param userId
*/
void deleteUser(Integer userId);
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 根据姓名模糊查询
* @param username
* @return
*/
List<User> findByName(String username);
/**
* 查询总用户数
* @return
*/
int findTotal();
/**
* 根据queryVo中的条件查询用户
* @param vo
* @return
*/
List<User> findUserByVo(QueryVo vo);
}
1.2 修改相应的IUserDao.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="fang.dao.IUserDao">
<!-- 配置查询所有-->
<select id="findAll" resultType="fang.domain.User">
select * from user
</select>
<!--保存用户-->
<!--User中的id字段是自动插入的,配置的selectKey帮助我们插入后获取id值-->
<!--value中的字段#{username}名称需要和传入的User对象的属性名称一样-->
<!--使用#{username}会有占位符,防止Sql注入。而使用${username}是字符串拼接-->
<insert id="saveUser" parameterType="fang.domain.User">
<!-- 配置插入操作后,获取插入数据的id -->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username, address, sex, birthday) values(#{username},#{address},#{sex},#{birthday});
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="fang.domain.User">
update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
</update>
<!--删除用户-->
<delete id="deleteUser" parameterType="java.lang.Integer">
delete from user where id = #{id};
</delete>
<!--根据id查询用户信息-->
<!--因为传入的参数就一个,所以这里的uid可以随便写名称-->
<select id="findById" parameterType="INT" resultType="fang.domain.User">
select * from user where id = #{uid};
</select>
<!--根据姓名模糊查询-->
<select id="findByName" parameterType="String" resultType="fang.domain.User">
select * from user where username like #{name};
<!-- select * from user where username like '%${value}%'; -->
</select>
<!--查询总用户数-->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
<!--根据queryVo的条件查询用户-->
<select id="findUserByVo" parameterType="fang.domain.QueryVo" resultType="fang.domain.User">
select * from user where username like #{user.username};
</select>
</mapper>
- 需要注意下面一些内容:
- resultType是函数的返回值类型,parameterType是函数传入的参数类型
- 不同的操作用不同的标签,常用的有select,insert,update,delete标签。
- 根据姓名模糊查询中需要传入的参数如:%name%
- queryVo为传入的包装类
1.3 编写QueryVo传递 pojo 包装对象
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),
这时可以使用包装对象传递输入参数。
Pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
- 编写QueryVo如下
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
1.4 编写测试类
- 在测试类中我们使用单元测试@Test注解
- @Before注解是测试代码之前执行的函数
- @After注解是测试代码执行完成之后执行的
- 由于没有自动开启提交事务,所以保存操作会自动回滚,所以我们在@After中添加了提交事务代码
public class MybatisTest {
private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;
@Before //用于在测试方法执行之前执行
public void init() throws Exception {
//1.读取配置文件
in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
sqlSession = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After //用于在测试方法执行之后执行
public void destory() throws Exception {
sqlSession.commit();
sqlSession.close();
in.close();
}
/**
* 测试查询所有操作
*/
@Test
public void testFindAll() {
List<User> users = userDao.findAll();
for(User user: users) {
System.out.println(user);
}
}
/**
* 测试保存操作
*/
@Test
public void testSave() {
User user = new User();
user.setUsername("mybatis last insertId");
user.setAddress("北京");
user.setSex("男");
user.setBirthday(new Date());
System.out.println(user);
//5.执行保存方法
userDao.saveUser(user);
System.out.println(user);
}
/**
* 测试更新操作
*/
@Test
public void testUpdate() {
User user = new User();
user.setId(50);
user.setUsername("mybatis update");
user.setAddress("北京");
user.setSex("女");
user.setBirthday(new Date());
userDao.updateUser(user);
}
/**
* 测试删除操作
*/
@Test
public void testDelete() {
userDao.deleteUser(48);
}
/**
* 测试根据id查询用户信息操作
*/
@Test
public void testFindOne() {
User user = userDao.findById(50);
System.out.println(user);
}
/**
* 测试根据名字模糊查询用户信息操作
*/
@Test
public void testFindByName() {
List<User> users = userDao.findByName("%王%");
// List<User> users = userDao.findByName("王");
for (User user : users) {
System.out.println(user);
}
}
/**
* 测试查询总记录条数
*/
@Test
public void testFindTotal() {
int count = userDao.findTotal();
System.out.println(count);
}
/**
* 测试使用QueryVo作为查询条件
*/
@Test
public void testFindByVo() {
QueryVo vo = new QueryVo();
User user = new User();
user.setUsername("%王%");
vo.setUser(user);
List<User> users = userDao.findUserByVo(vo);
for (User u : users) {
System.out.println(u);
}
}
}
- 到这里,基本的增删改查的操作就完成了
2. Mybatis部分细节详解 |
2.1 当数据库中的字段和我们写的实体类不一样时,怎么操作?
- 例如我们的User类中的字段改成如下片段
public class User implements Serializable { private Integer userId; //id private String userName; //username private Date userBirthday; //birthday private String userSex; //sex private String userAddress; //address }
-
我们需要将IUserDao.xml中的 #{username},#{address}等字段均改为#{userName},#{userAddress}
例如:<insert id="saveUser" parameterType="fang.domain.User"> <!-- 配置插入操作后,获取插入数据的id --> <!--keyProperty是属性字段,keyColumn是数据库字段--> <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER"> select last_insert_id(); </selectKey> insert into user(username, address, sex, birthday) values(#{userName},#{userAddress},#{userSex},#{userBirthday}); </insert>
-
上述改完后还有查询语句只有username有数据,有数据是因为mysql不区分大小写。切记:在linux系统中是区分大小写的,有两种方式解决:
- 用as字段,如下:
<!-- 配置查询所有--> <select id="findAll" resultType="fang.domain.User"> select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user </select>
- 采用配置的方式:
<!--配置查询结果的列名和实体类属性名的对应关系--> <resultMap id="userMap" type="fang.domain.User"> <!--主键字段的对应--> <id property="userId" column="id"/> <!--非主键字段的对应--> <result property="userName" column="username"/> <result property="userAddress" column="address"/> <result property="userSex" column="sex"/> <result property="userBirthday" column="birthday"/> </resultMap> <!-- 配置查询所有--> <!--resultType="fang.domain.User改成resultMap--> <select id="findAll" resultMap="userMap"> select * from user </select>
-
2.2 将数据库信息用properties文件保存,工程直接引用文件。
-
编写jdbcConfig.properties文件保存到resources目录(类路径)下
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis jdbc.username=root jdbc.password=root
-
SqlMapConfig.xml中的内容修改如下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--mybatis的主配置文件--> <configuration> <properties resource="jdbcConfig.properties"/> <!--<properties url="file:///D:\IdeaProjects\JavaStudy\eesy_mybatis\src\main\resources\jdbcConfig.properties"/>--> <!--配置环境--> <environments default="mysql"> <!-- 配置mysql的环境--> <environment id="mysql"> <!-- 配置的事务的类型--> <transactionManager type="JDBC"></transactionManager> <!-- 配置数据源(连接池)--> <dataSource type="POOLED"> <!-- 配置连接数据库的4个基本信息--> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件--> <mappers> <!-- <mapper resource="fang/dao/IUserDao.xml"></mapper>--> <package name="fang.dao"/> </mappers> </configuration>
- 配置了properties属性,可以在标签类配置连接数据库的信息,也可以通过属性引用外部配置文件信息。
- resource属性用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。
- 若使用的不是resource属性,而是url属性,这需要在自己目录中找到file位置
2.3 引用typeAliases(类型别名)和mapper(映射器)
-
在SqlMapConfig.xml中配置,配置完后就可以直接按使用别名,不用写全名了。别名不区分大小写。
<typeAliases> <!-- 单个别名定义 --> <!--<typeAlias alias="user" type="fang.domain.User"/>--> <!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> <package name="fang.domain"/> </typeAliases>
-
在SqlMapConfig.xml中配置mapper映射器
<mappers> <!--<mapper resource="fang/dao/IUserDao.xml"></mapper>--> <package name="fang.dao"/> </mappers>
之前有多少配置文件就需要写几个mapper,现在使用package就不用啦。