目录结构
- 实体类:QueryVo
package cn.luis.domain;
/**
* @ClassName QueryVo
* @Description 由多个对象组成一个查询条件实现数据的查询
* @Author L
* @Date 2020.03.01 20:32
* @Version 1.0
* @Remark TODO
**/
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
- IUserDao.java
package cn.luis.dao;
import cn.luis.domain.QueryVo;
import cn.luis.domain.User;
import java.util.List;
/**
* @InterfaceName IUserDao
* @Description 用户的持久层接口
* @Author L
* @Date 2020.02.29 15:31
* @Version 1.0
* @Remark TODO
**/
public interface IUserDao {
/**
* @Description 查询所有用户
**/
List<User> findAll();
/**
* @Description 保存用户
**/
void saveUser(User user);
/**
* @Description 更新用户
* @Return void
**/
void updateUser (User user);
/**
* @Description 根据Id删除用户
**/
void deleteUser(Integer userId);
/**
* @Description 根据Id查询用户信息
**/
User findById(Integer userId);
/**
* @Description 根据名称,模糊查询用户信息
**/
List<User> findByName(String username);
/**
* @Description 查询总用户数
**/
int findTotal();
/**
* @Description 根据queryVo中的条件查询用户
* 把查询条件对象作为参数传递
**/
List<User> findUserByVo(QueryVo vo);
}
- IUserao.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="cn.luis.dao.IUserDao">
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 【开发效率高】-->
<resultMap id="userMap" type="cn.luis.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="birthday"></result>
</resultMap>
<!--查询所有 【resultType】:结果集类型(封装到哪里去)-->
<!--<select id="findAll" resultType="cn.luis.domain.User">-->
<select id="findAll" resultMap="userMap">
select * from user;
<!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user; 【执行效率高】-->
</select>
<!--保存用户 parameterType:参数类型 【OGNL表达式】:#{实体类属性名称}-->
<insert id="saveUser" parameterType="cn.luis.domain.User">
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
<!-- 插入操作成功后,获取插入数据的Id -->
<!-- 【keyProperty】:Id属性名(实体类)【keyColumn】:Id列名(表) 【order】: 什么时候执行获取Id操作 【After】:在插入之后 -->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="cn.luis.domain.User">
update user set username=#{userName},address=#{userAddress},sex=#{userSex},birthday=#{userBirthday} where id = #{userId};
</update>
<!--删除用户 【uid:占位符】,参数是基本类型或者基本类型包装类时,并且只有一个时,可随意命名-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id = #{uid};
</delete>
<!--根据Id查询用户-->
<select id="findById" parameterType="INT" resultMap="userMap">
select * from user where id = #{uid};
</select>
<!--根据名称,模糊查询用户-->
<select id="findByName" parameterType="String" resultMap="userMap">
<!--【预处理方式】:like ? -->
<!--select * from user where username like #{name};-->
<!--【字符串拼接方式】 :like %小% -->
select * from user where username like '%${value}%';
</select>
<!--获取用户的总记录条数-->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
<!-- 根据queryVo的条件查询用户 -->
<!-- 【#{user.username}】:在QueryVo中有user属性,user是对象,要调用它的属性username -->
<select id="findUserByVo" parameterType="cn.luis.domain.QueryVo" resultMap="userMap">
select * from user where username like #{user.username};
</select>
</mapper>
- 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>
<!-- 配置环境 -->
<environments default="mysql">
<!-- 配置mysql的环境-->
<environment id="mysql">
<!-- 配置事务的类型-->
<transactionManager type="JDBC"></transactionManager>
<!-- 配置数据源(连接池) -->
<dataSource type="POOLED">
<!-- 配置连接数据库的4个基本信息 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="cn/luis/dao/IUserMapper.xml"/>
</mappers>
</configuration>
- 测试类
package cn.luis.test;
import cn.luis.dao.IUserDao;
import cn.luis.domain.QueryVo;
import cn.luis.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
/**
* @ClassName MybatisTest
* @Description 测试mybatis的CRUD操作
**/
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
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
// 3.获取sqlsession对象
sqlSession = factory.openSession();
// 4.获取dao的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
// 用于在测试方法执行完成后执行
@After
public void destory() throws Exception {
// 提交事务
sqlSession.commit();
// 6.释放资源
sqlSession.close();
in.close();
}
/**
* @Description 查询所有 (mysql在windows下不区分大小写,所以能把username封装到userName中)
**/
@Test
public void testFindAll() {
// 5.执行所有方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
}
/**
* @Description 测试保存操作
**/
@Test
public void testFindSave() {
User user = new User();
user.setUserName("mybatis last insertid");
user.setUserAddress("沈阳");
user.setUserSex("男"); // 查看数据库这里的赋值类型
user.setUserBirthday(new Date());
System.out.println("保存操作之前:" + user);
// 5.执行保存方法
userDao.saveUser(user);
System.out.println("保存操作之后:" + user);
}
/**
* @Description 测试更新操作
**/
@Test
public void testUpdate() {
User user = new User();
// 给id赋值
user.setUserId(45);
user.setUserName("mybatis updateuser");
user.setUserAddress("沈阳");
user.setUserSex("女"); // 查看数据库这里的赋值类型
user.setUserBirthday(new Date());
// 5.执行保存方法
userDao.updateUser(user);
}
/**
* @Description 测试删除操作
**/
@Test
public void testDelete() {
// 5.执行删除方法
userDao.deleteUser(49);
}
/**
* @Description 测试查询一个方法
**/
@Test
public void testFindOne() {
User user = userDao.findById(45);
System.out.println(user);
}
/**
* @Description 测试模糊查询操作
**/
@Test
public void testFindByName() {
//List<User> users = userDao.findByName("%小%");
List<User> users = userDao.findByName("小");
for (User user : users) {
System.out.println(user);
}
}
/**
* @Description 测试查询总记录条数
* 支持聚合函数的查询
**/
@Test
public void testFindTotal() {
int count = userDao.findTotal();
System.out.println(count);
}
/**
* @Description 测试查询总记录条数
**/
@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);
}
}
}
OGNL表达式
Object Graphic Navigation Language
对象 图 导航 语言
它是通过对象的取值方法来获取数据。在写法上把get给省略了。
比如:我们获取用户的名称:
- 类中的写法:user.getUsername();
- OGNL表达式写法:user.username
mybatis中为什么能直接写username,而不用user呢?
因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名
parameterType(输入类型)
可以传递简单类型,也可以传递pojo对象
Mybatis 使用ognl表达式解析对象字段的值,#{}或者${}括号中的值为pojo属性名称。
传递pojo对象
开发中通过pojo传递查询条件,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo类中包含pojo。
需求:根据用户名查询用户信息,查询条件放到QueryVo的user属性中。
Mapper.xml文件
<!-- 根据queryVo的条件查询用户 -->
<!-- 【#{user.username}】:在QueryVo中有user属性,user是对象,要调用它的属性username -->
<select id="findUserByVo" parameterType="cn.luis.domain.QueryVo" resultMap="userMap">
select * from user where username like #{user.userName};
</select>
Mapper接口
/**
* @Description 根据queryVo中的条件查询用户
* 把查询条件对象作为参数传递
**/
List<User> findUserByVo(QueryVo vo);
测试类
/**
* @Description 测试查询总记录条数
**/
@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);
}
}
结果:
User{userId=41, userName='老王', userAddress='北京', userSex='男', userBirthday=Tue Feb 27 17:47:08 CST 2018}
User{userId=42, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Fri Mar 02 15:09:37 CST 2018}
User{userId=43, userName='小二王', userAddress='北京金燕龙', userSex='女', userBirthday=Sun Mar 04 11:34:34 CST 2018}
User{userId=46, userName='老王', userAddress='北京', userSex='男', userBirthday=Wed Mar 07 17:37:26 CST 2018}
具体代码见上!
resultType(输出类型)
- 可以输出简单类型
<!--获取用户的总记录条数-->
<select id="findTotal" resultType="int">
select count(id) from user;
</select>
- 可以输出pojo对象(查询一个)
<!--根据Id查询用户-->
<select id="findById" parameterType="INT" resultType="cn.luis.domain.User">
select * from user where id = #{uid};
</select>
- 可以输出polo列表(查询所有)
<!--根据名称,模糊查询用户-->
<select id="findByName" parameterType="String" resultType="cn.luis.domain.User">
<!--【预处理方式】:like ? -->
<!--select * from user where username like #{name};-->
<!--【字符串拼接方式】 :like %小% -->
select * from user where username like '%${value}%';
</select>
测试类
@Test
public void testFindByName() {
//【预处理方式】:like ? --> 【推荐】
List<User> users = userDao.findByName("%小%");
// 【字符串拼接方式】 :like %小% -->
// List<User> users = userDao.findByName("小");
for (User user : users) {
System.out.println(user);
}
}
CRUD中可能遇到的问题
1. 参数的传递以及返回值的封装
- mysql在windows下不区分大小写,所以能把username封装到userName中
要修改OGNL表达式中的实体类属性名称与之匹配才行
<!--保存用户 parameterType:参数类型 OGNL表达式:#{实体类属性名称}-->
<insert id="saveUser" parameterType="cn.luis.domain.User">
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
<!-- 插入操作成功后,获取插入数据的Id -->
<!-- keyProperty:Id属性名(实体类)keyColumn:Id列名(表) order: 什么时候执行获取Id操作 After:在插入之后 -->
<selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
</insert>
2. 解决实体类属性和数据库列名不对应的两种方式
- 在sql语句中起别名 【执行效率高】
<!--查询所有 【resultType】:结果集类型(封装到哪里去)-->
<select id="findAll" resultType="cn.luis.domain.User">
<!-- select * from user; -->
select id as userId,username as userName,address as userAddress,
sex as userSex,birthday as userBirthday from user;
</select>
-
采用配置resultMap方式 【开发效率高】
配置查询结果的类名和实体类属性名的对应关系
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 【开发效率高】-->
<resultMap id="userMap" type="cn.luis.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="birthday"></result>
</resultMap>
<!--查询所有 【resultType】:结果集类型(封装到哪里去)-->
<select id="findAll" resultMap="userMap">
select * from user;
</select>