一、Mapper接口来实现CRUD
1.1 接口映射
接口映射:mybatis提供了一种可以通过调用接口中的方法实现调用对应的SQL语句,xxxx.fun(user);
接口: 接口对应指定的mapper文件
映射:使用接口与对应的mapper文件形成映射关系,操作接口就是在操作mapper文件
要求
1.接口的名字最好与mapper的名字相同
2.接口与mapper最好在同一个包下
3.mapper文件的namespace必须是对应接口的类型全名
4.mapper中SQL的id必须与接口中对应的方法名相同
5.在mybatis的主配置文件中需要扫描mapper、接口所在的包
1.2 代码实现
在昨天的测试类中,我们进行测试的方法为
session.insert("abc.add", user);
不符合面对接口编程的思想,于是我们创建UserMapper接口来实现CRUD
1.2.1 UserMapper.java接口
package com.woniuxy.mapper;
import java.util.List;
import java.util.Map;
import com.woniuxy.entity.User;
public interface UserMapper {
// 全查询,返回List
public List<User> findAll();
// 添加
public int add(User user);
// 删除
public int delById(int id);
// 修改
public int changePwd(Map<String, Object> map);
}
注意:其中,方法名对应UserMapper.xml中CRUD的id
1.2.2 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">
<!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
<mapper namespace="com.woniuxy.mapper.UserMapper">
<!-- 二级缓存:
指定当前mapper中所有SQL语句查询到的数据都可以“可以”放到二级缓存中,建议为只读
触发:需要session.commit()提交后或session.close()关闭后才会存入二级缓存
-->
<cache readOnly="true"></cache>
<!-- id为SQL的唯一标识,同一命名空间下不能有id相同的SQL
resultType:将查询出来的数据封装成什么类型的对象
-->
<select id="findAll" resultType="com.woniuxy.entity.User">
select * from mall_user
</select>
<!-- 增 -->
<insert id="add">
insert into mall_user
values (default,#{account},#{password},#{email},
#{avatar},#{score},#{regtime},#{status})
</insert>
<!-- 删
如果参数是基本数据类型、包装类、string类型,获取参数时名字可以随意取
但是建议与要操作的字段名字保持一致
-->
<delete id="delById">
delete from mall_user where id = #{id};
</delete>
<!-- 改 -->
<update id="changePwd">
update mall_user set password = #{password} where account = #{account}
</update>
</mapper>
注意:
**
1.2.3 UserMapperTest.java 测试类
package com.woniuxy.test;
import java.io.IOException;
import java.io.InputStream;
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 com.woniuxy.mapper.GoodsMapper;
public class UserMapperTest {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
// 获取mapper对象,利用动态代理自动生成了实现该接口的实现类,自动创建该类型的对象
// UserMapper userMapper = session.getMapper(UserMapper.class);
// System.out.println(userMapper.findAll());
// 获取mapper对象,利用动态代理自动生成了实现该接口的实现类,自动创建该类型的对象
GoodsMapper goodsMapper = session.getMapper(GoodsMapper.class);
// 全查询商品
// System.out.println(goodsMapper.findAll());
// 根据ID查询商品
// System.out.println(goodsMapper.findById(150));
// 根据名字模糊查询商品
System.out.println(goodsMapper.findByNameLike("%IT%"));
session.close();
}
}
可见,上述方法实现了 接口.方法名来实现CRUD,从而实现了面向接口编程
二、mybatis的自动映射
自动映射:mybatis根据查询出来的“结果集”,自动将数据封装成指定类型的对象
第一层含义:对象中的数据只能包含结果集中的数据
第二层含义:mybatis在进行自动映射时是根据结果集的字段名找到对应的setter给对应的属性赋值
在使用mybatis时,创建entity对象时,它的属性应该与表中的字段名保持一致
2.1 起别名(不常用)
user
uid uname uage
select uid id,
User
id name age
2.2 手动映射(常用)
手动映射:程序员自己指定映射规则,哪些字段的值映射到哪些属性上
三、@Param
3.1 使用之前
GoodsMapper接口中的方法
public int findByPage(Map<String, Object> map);
GoodsTest测试类中的实现
//分页查询
Map<String, Object> params = new HashMap<String, Object>();
params.put("index", (page-1)*size);
params.put("size", size);
System.out.println(goodsMapper.findByPage(params));
3.2 使用@Param注解
GoodsMapper接口中的方法
// @Param 自动将参数封装到map中,其中的("index")为key,参数的值为value
// 此处参数名不重要,重要的是("index")是否正确
public List<Goods> findByPage(@Param("index")int index,@Param("size")int size);
GoodsTestMapper测试类中的实现
System.out.println(goodsMapper.findByPage(5, 10));
四、mybatis缓存
mybatis自带缓存,缓存是用临时存储数据,主要是为了提高查询效率
mybatis提供两种缓存:一级缓存,二级缓存
4.1 一级缓存
session缓存,session级别的缓存,只缓存当前session查询到的数据,每个session都有自己的缓存,在查询时session首先会先到自己的缓存中去查看是否有满足需求的数据,如果有则直接从缓存中获取到数据,否则执行SQL查询数据,然后将查询到的数据放到一级缓存中
4.2 二级缓存
factory缓存,factory级别的缓存,只要是通过该工厂创建出来的session查询到的数据都可以放到factory缓存中,所有的session就可以共享
注意:不是什么数据都往里面放,是那些使用非常频繁的数据才往里面扔,所有mybatis在运行时默认不会将session查询到的数据放到二级缓存中,而是需要程序员告诉mybatis哪些数据需要放到二级缓存,mybatis才会将这些数据放到二级缓存中
告诉mybatis的方法是在mapper文件中通过cache标签指定当前mapper查询到的数据可以存放到二级缓存中
在xml中添加
<!-- 二级缓存:
指定当前mapper中所有SQL语句查询到的数据都可以“可以”放到二级缓存中,建议为只读
触发:需要session.commit()提交后或session.close()关闭后才会存入二级缓存
-->
<cache readOnly="true"></cache>
其位置在
五、手动映射
5.1 User2实体类
我们手动制造出表中列名与实体类中的属性名无法自动映射的情况
package com.woniuxy.entity;
import java.util.Date;
import lombok.Data;
@Data
public class User2 {
private int uid; //id
private String uaccount; //账号
private String upassword; //密码
private String uemail; //邮箱
private String uavatar; //头像
private int uscore; //积分
private Date uregtime; //注册时间
private String ustatus; //状态
}
5.2 UserMapper.java接口
package com.woniuxy.mapper;
import java.util.List;
import java.util.Map;
import com.woniuxy.entity.User;
import com.woniuxy.entity.User2;
public interface UserMapper2 {
//all
public List<User2> findAll();
}
5.3 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.woniuxy.mapper.UserMapper2">
<select id="findAll" resultMap="abc">
select * from mall_user
</select>
<!-- 自定义映射规则
type:将数据封装成指定类型的对象
-->
<resultMap type="User2" id="abc">
<!-- 指定主键的映射关系:必须指定 -->
<id column="id" property="uid"/>
<!-- 非主键列的映射规则 -->
<result column="account" property="uaccount"/>
<result column="password" property="upassword"/>
<result column="email" property="uemail"/>
<result column="avatar" property="uavatar"/>
<result column="score" property="uscore"/>
<result column="regtime" property="uregtime"/>
<result column="status" property="ustatus"/>
</resultMap>
</mapper>
5.4 UserMapper2Test测试类
package com.woniuxy.test;
import java.io.InputStream;
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 com.woniuxy.mapper.UserMapper2;
public class UserMapper2Test {
public static void main(String[] args)throws Exception {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
UserMapper2 userMapper2 = session.getMapper(UserMapper2.class);
System.out.println(userMapper2.findAll());
session.close();
}
}
六、映射关系
类与类之间的映射关系
一对一:一个husband一个wife、一个person对应一张card
一对多:一个班级多个学生、一个公司多个职员、一个家庭多个成员
多对一:多个学生一个班级
多对多:多个老板对应多个公司、多个班级多个老师
七、一对一映射
7.1 实体类
7.1.1 Husband
package com.woniuxy.entity;
import lombok.Data;
@Data
public class Husband {
private int hid;
private String hname;
private Wife wife;
}
7.1.2 Wife
package com.woniuxy.entity;
import lombok.Data;
@Data
public class Wife {
private int wid;
private String wname;
}
7.2 接口
HusbandMapper.java 接口
package com.woniuxy.mapper;
import com.woniuxy.entity.Husband;
public interface HusbandMapper {
// 根据丈夫的id查询到他自己的信息及其配偶的信息
public Husband findByHid(int id);
}
7.3 XML文件
HusbandMapper.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">
<!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
<mapper namespace="com.woniuxy.mapper.HusbandMapper">
<!-- 通过外键判断进行连表查询 -->
<select id="findByHid" resultMap="husbandMap">
select * from husband h,wife w where h.hid = w.hid and h.hid=#{hid}
</select>
<resultMap type="Husband" id="husbandMap">
<!-- 指定主键的映射关系:必须指定,就算能自动映射也要写
如果查询语句是连表查询,所有字段、属性的映射关系都必须指定
-->
<id column="hid" property="hid"/>
<result column="hname" property="hname"/>
<!-- 指定一对一的关系
property:属性名 javaType:该属性的类型
-->
<association property="wife" javaType="Wife">
<id column="wid" property="wid"/>
<result column="wname" property="wname"/>
</association>
</resultMap>
</mapper>
7.4 测试类
OneToOneTest 测试类
package com.woniuxy.test;
import java.io.IOException;
import java.io.InputStream;
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 com.woniuxy.mapper.HusbandMapper;
public class OneToOneTest {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);
通过外键判断进行连表查询
System.out.println(husbandMapper.findByHid(1001));
}
}
7.5 n+1查询
7.5.1 Husband.java接口
package com.woniuxy.mapper;
import com.woniuxy.entity.Husband;
public interface HusbandMapper {
// 根据丈夫的id查询到他自己的信息及其配偶的信息
public Husband findByHid(int id);
// 使用n+1的方法查询
public Husband findByHid2(int id);
}
7.5.2 Husband.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">
<!-- namespace:命名空间,作用与包名一样,区分相同id的SQL -->
<mapper namespace="com.woniuxy.mapper.HusbandMapper">
<!-- 通过外键判断进行连表查询 -->
<select id="findByHid" resultMap="husbandMap">
select * from husband h,wife w where h.hid = w.hid and h.hid=#{hid}
</select>
<resultMap type="Husband" id="husbandMap">
<!-- 指定主键的映射关系:必须指定,就算能自动映射也要写
如果查询语句是连表查询,所有字段、属性的映射关系都必须指定
-->
<id column="hid" property="hid"/>
<result column="hname" property="hname"/>
<!-- 指定一对一的关系
property:属性名 javaType:该属性的类型
-->
<association property="wife" javaType="Wife">
<id column="wid" property="wid"/>
<result column="wname" property="wname"/>
</association>
</resultMap>
<!-- n+1多表查询 -->
<select id="findByHid2" resultMap="nMap">
select * from husband where hid = #{hid}
</select>
<resultMap type="Husband" id="nMap">
<id column="hid" property="hid"/>
<!-- column:表示哪一个字段的值作为查询条件,去调用第二条SQL语句
select:需要调用的SQL语句id
-->
<association property="wife" column="hid" select="findWifeByHid"></association>
</resultMap>
<select id="findWifeByHid" resultType="Wife">
select * from wife where hid = #{hid}
</select>
</mapper>
7.5.3 OneToOneTest 测试类
package com.woniuxy.test;
import java.io.IOException;
import java.io.InputStream;
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 com.woniuxy.mapper.HusbandMapper;
public class OneToOneTest {
public static void main(String[] args) throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
HusbandMapper husbandMapper = session.getMapper(HusbandMapper.class);
// 通过外键判断进行连表查询
// System.out.println(husbandMapper.findByHid(1001));
// n + 1查询
System.out.println(husbandMapper.findByHid2(1001));
}
}