使用要求:
1、持久层接口和持久层接口的映射配置必须在相同的包下
2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
3、SQL 语句的配置标签<select>,<insert>,<delete>,<update>的 id 属性必须和持久层接口的方法名相同
一:在持久层接口加中添加方法
package com.itheima.dao;
import com.itheima.domain.QueryVo;
import com.itheima.domain.User;
import java.util.List;
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有用户
* @return
*/
List<User> findAll();
/**
* 新增用户
* @param user
*/
void saveUser(User user);
/**
* 更新用户
* @param user
*/
void updateUser(User user);
/**
* 删除用户
* @param id
*/
void deleteUser(Integer id);
/**
* 根据id查询用户
* @param userId
*/
User findById(Integer userId);
/**
* 根据名称模糊查询
* @param name
* @return
*/
List<User> findByName(String name);
/**
* 查询总记录数
*
*/
int findTotal();
/**
* 根据QueryVo中的条件查询
* @param vo
* @return
*/
List<User> findByVo(QueryVo vo);
}
二:在用户的映射文件中配置
<?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.itheima.dao.IUserDao">
<!--查询所有-->
<select id="findAll" resultType="com.itheima.domain.User">
select * from user;
</select>
<!--保存用户-->
<insert id="saveUser" parameterType="com.itheima.domain.User">
<!--配置插入操作后获取数据id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday)value(#{username},#{address},#{sex},#{birthday});
</insert>
<!--更新用户-->
<update id="updateUser" parameterType="com.itheima.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>
<!--查询一个用户-->
<select id="findById" parameterType="int" resultType="com.itheima.domain.User">
select * from user where id=#{uid};
</select>
<!--根据名称模糊查询-->
<select id="findByName" resultType="com.itheima.domain.User" parameterType="String">
select * from user where username like #{name};
</select>
<!--查询总记录数-->
<select id="findTotal" resultType="int">
select count(id) from user ;
</select>
<!--根据用户名称模糊查询,参数变成一个 QueryVo 对象了 -->
<select id="findByVo" resultType="com.itheima.domain.User" parameterType="com.itheima.domain.QueryVo">
select * from user where username like #{user.username}
</select>
</mapper>
三、在测试类中新增测试方法
package com.itheima.test;
import com.itheima.dao.IUserDao;
import com.itheima.domain.QueryVo;
import com.itheima.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;
public class MybatisTest {
InputStream in;
SqlSession session;
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对象
session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
userDao = session.getMapper(IUserDao.class);
}
@After
public void destroyed() throws Exception{
session.commit();
//6.释放资源
session.close();
in.close();
}
@Test
public void testFindAll() {
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
}
@Test
public void testSaveUser(){
User user = new User();
user.setUsername("张三");
user.setAddress("北京");
user.setSex("男");
user.setBirthday(new Date());
System.out.println("添加之前:"+user);
userDao.saveUser(user);
System.out.println("添加之后:"+user);
}
@Test
public void testUpdateUser(){
User user = new User();
user.setId(50);
user.setUsername("李四");
user.setAddress("山西");
user.setSex("男");
user.setBirthday(new Date());
userDao.updateUser(user);
}
@Test
public void testDeleteUser(){
userDao.deleteUser(50);
}
@Test
public void testFindOne(){
User user = userDao.findById(45);
System.out.println(user);
}
@Test
public void testFindByName(){
List<User> users = userDao.findByName("%王%");
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testFindTotal(){
int total = userDao.findTotal();
System.out.println(total);
}
@Test
public void testFindByVo(){
User user = new User();
user.setUsername("%王%");
QueryVo vo = new QueryVo();
vo.setUser(user);
List<User> users = userDao.findByVo(vo);
for (User u : users) {
System.out.println(u);
}
}
}
问题扩展:新增用户 id 的返回值
新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。
<insert id="saveUser" parameterType="com.itheima.domain.User">
<!--配置插入操作后获取数据id-->
<selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
select last_insert_id();
</selectKey>
insert into user(username,address,sex,birthday)value(#{username},#{address},#{sex},#{birthday});
</insert>
keyProperty=“实体类id”
keyColumn=“表中id”
resultType=“int” 封装结果类型
order=“AFTER” 在新增之后执行
问题新增: 参数类型 parameterType的写法
1、基本类型 和 String 我们可以直接写类型名称 ,也可以使用 包名 . 类名 的方式 ,例java.lang.String。
2、实体类类型,目前我们只能使用全限定类名。
原因是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,而我们的是实体类并没有注册别名,所以必须写全限定类名。
问题扩展:传递 pojo 包装对象
POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBean
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
编写 QueryVo
/**
* <p>Description: 查询条件对象</p>
*/
public class QueryVo implements Serializable {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
问题新增:#{} 与${} 的区别
#{} 表示一个占位符号
1、通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,#{}可以有效防止 sql 注入。
2、#{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。
OGNL表达式:
Object Graphic Navigation Language
对象 图 导航 语言
它是通过对象的取值方法来获取数据。在写法上把get给省略了。
比如:我们获取用户的名称
类中的写法:user.getUsername();
OGNL表达式写法:user.username
mybatis中为什么能直接写username,而不用user.呢:
因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名
pojo属性值:#{username}相当于User.getUsername
简单类型值:#{value} 参数值写什么就是什么
${} 表示拼接 sql 串
1、通过${}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换
2、 ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
Mybatis 的输出结果封装
resultType 结果类型
1、resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。
2、需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须使用全限定类名。
3、同时,当是实体类名称是domain的时候,还有一个要求,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法实现封装
resultMap 结果类型
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。
<!-- 建立 User 实体和数据库表的对应关系
type 属性:指定实体类的全限定类名
id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
<resultMap type="com.itheima.domain.User" id="userMap">
<id column="id" property="userId"/>
<result column="username" property="userName"/>
<result column="sex" property="userSex"/>
<result column="address" property="userAddress"/>
<result column="birthday" property="userBirthday"/>
</resultMap>
<!--id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
-->
<!-- 配置查询所有操作 -->
<select id="findAll" resultMap="userMap">
select * from user
</select>