方便后面分测试;
//获取SqlSessionFactory 对象的通用方法
public SqlSessionFactory getSqlSessionFactory() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
return new SqlSessionFactoryBuilder().build(inputStream);
}
| 属性名 | 说明 |
|---|---|
| id | namespace指定接口中的方法名 |
| parameterType | 指定接口方法入参类型,可写可不写(mybatis可用根据接口方法,自动推断类型) |
| useGeneratedKey | insert标签的属性,告诉mybatis,执行插入操作,需要返回自增的主键 |
| keyColumn | 自增主键的 字段名(可以不写,一张表只用能有一个自增主键) |
| keyPropert | 指定返回的自增主键值,交给入参实体的哪个属性保存 |
注意:增删改操作,和select查询标签最大的区别是:返回只有影响行数,所有没有resultType属性,而查询必须有resultType;
<!-- int insertAnime(Anime animeForm); -->
<insert id="insertAnime" useGeneratedKeys="true" keyColumn="id" keyProperty="id" >
insert into `animes`(
`cid`,
`name`
)values(
#{cid},
#{name}
)
</insert>
注意:mybatis 默认对增删改操作,事务是不自动提交(自动提交是关闭的);
需要开启自动提交,或这是手动提交;
| 开启自动提交 | openSession(true); |
|---|---|
| 手动提交 | sqlSession.commit(); |
@Test
public void testMybatisMapperC() throws IOException {
//获取SqlSession对象
// SqlSession sqlSession = getSqlSessionFactory().openSession();
//方式2:创建SqlSession对象时,指定事务自动提交-true,默认false
SqlSession sqlSession = getSqlSessionFactory().openSession(true);
//获取mapper接口的代理实现对象
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
System.out.println(animeMapper); //org.apache.ibatis.binding.MapperProxy@224edc67
//模拟从前端获取参数,封装请求实体
Anime animeForm = new Anime();
animeForm.setCid(1);
animeForm.setName("蜡笔小新");
//执行添加动漫
int row = animeMapper.insertAnime(animeForm);
//mybatis 默认对增删改操作,事务是不自动提交(自动提交是关闭的)
//方式1:手动提交
//sqlSession.commit();
System.out.println(String.format("----------执行添加动漫,影响行数:%d--------", row));
//获取自增主键
System.out.println(String.format("----------执行添加动漫,新增的自增id:%d--------", animeForm.getId()));
}
<!-- int updateAnimeById(Anime animeForm); -->
<update id="updateAnimeById">
update `animes` set
`cid` = #{cid},
`name` = #{name}
where `id` = #{id}
</update>
@Test
public void testMybatisMapperU() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession(true);
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//模拟从前端获取参数,封装请求实体
Anime animeForm = new Anime();
animeForm.setId(648);
animeForm.setCid(1);
animeForm.setName("蜡笔小新5");
//执行修改动漫
int row = animeMapper.updateAnimeById(animeForm);
System.out.println(String.format("----------执行修改动漫,影响行数:%d--------", row));
}
<!-- int deleteAnimeById(Integer animeId); -->
<delete id="deleteAnimeById">
delete from `animes`
where `id` = #{animeId}
</delete>
@Test
public void testMybatisMapperD() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession(true);
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//模拟从前端获取参数,封装请求实体
Anime animeForm = new Anime();
animeForm.setId(648);
//执行删除动漫
int row = animeMapper.deleteAnimeById(animeForm.getId());
System.out.println(String.format("----------执行删除动漫,影响行数:%d--------", row));
}
| 属性名 | 说明 |
|---|---|
| id | 对应就是namespace指定接口中的查询方法名 |
| parameterType | 指定接口方法入参类型,可写可不写(建议不写) |
| resultType | 指定接口返回的目标类型(建议使用全类名,也可以使用别名) |
接口只有一个参数,参数名,可以随便写,建议跟形参名保持一致;
<!-- Anime selectAnimeById(Integer animeId); -->
<select id="selectAnimeById" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `id` = #{animeId}
</select>
@Test
public void testMybatisMapperSelectParams1() throws IOException{
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//调用mapper接口,根据动漫编号查询动漫信息
Anime anime = animeMapper.selectAnimeById(101);
System.out.println(String.format("1.一个参数 根据动漫编号:%d,查询动漫详情%s",anime.getId(),anime));
}
多个参数,没有自定义参数别名时可以使用
自定义参数别名@Param("自定义参数名")时可以使用:
Anime selectAnimeByNameAndCid(String animeName,Integer animeId);
<!-- Anime selectAnimeByNameAndCid(String animeName,Integer animeId); -->
<select id="selectAnimeByNameAndCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `name` = #{animeName}
and `cid` = #{animeId}
<!--
where `name` = #{0}
and `cid` = #{1}
-->
<!--
where `name` = #{ param1}
and `cid` = #{param2}
-->
</select>
Anime selectAnimeByNameAndCid(@Param("animeName") String animeName,@Param("animeId") Integer animeId);
Anime selectAnimeByNameAndCid(@Param("animeName") String animeName,@Param("animeId") Integer animeId);
<select id="selectAnimeByNameAndCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `name` = #{animeName}
and `cid` = #{animeId}
<!--
where `name` = #{ param1}
and `cid` = #{param2}
-->
</select>
自定义了参数名,如果使用#{0},#{1}会报错
Cause: org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [animeId, animeName, param1, param2]
@Test
public void testMybatisMapperSelectParams2() throws IOException{
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//通过动漫名称和分类编号查询动漫信息
Anime anime = animeMapper.selectAnimeByNameAndCid("完美世界",3);
System.out.println(String.format("2.两个参数 根据动漫编号:%d,查询动漫详情%s",anime.getId(),anime));
}
不自定义参数别名:
自定义参数别名:
Anime selectAnimeByAnime(Anime animeForm);
<select id="selectAnimeByAnime" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `cid` = #{cid}
and `author` = #{author}
</select>
Anime selectAnimeByAnime(@Param("animeForm") Anime animeForm);
<select id="selectAnimeByAnime" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
<!--
where `cid` = #{animeForm.cid}
and `author` = #{animeForm.author}
-->
where `cid` = #{param1.cid}
and `author` = #{param1.author}
</select>
@Test
public void testMybatisMapperSelectParams3() throws IOException{
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//通过动漫分类编号和作者查询动漫信息
Anime animeForm = new Anime();
animeForm.setCid(1);
animeForm.setAuthor("三少");
Anime anime = animeMapper.selectAnimeByAnime(animeForm);
System.out.println(String.format("3.实体参数 根据动漫编号:%d,查询动漫详情%s",anime.getId(),anime));
}
<!--
Anime selectAnimeByActorAndCid(Map<String,Object> queryMap);
-->
<select id="selectAnimeByActorAndCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `cid` = #{cid}
and `actor` = #{actor}
</select>
@Test
public void testMybatisMapperSelectParams4() throws IOException{
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//通过动漫分类编号和主角查询动漫信息
Map<String,Object> queryMap = new HashMap<>();
queryMap.put("cid","2");
queryMap.put("actor","路飞");
Anime anime = animeMapper.selectAnimeByActorAndCid(queryMap);
System.out.println(String.format("4.集合参数 根据动漫编号:%d,查询动漫详情%s",anime.getId(),anime));
}
#{}:
类似于PreparedStatement
可以获取普通参数,自定义参数,实体参数,集合参数等;
底层使用的是?占位符,会进行预编译处理,可以防止SQL注入问题,安全性高;
不可以进行表达式运算;
${}:
类似于Statement
正常情况下,跟#{}获取参数的写法没有区别;
区别:不能随意获取参数,不能使用内置参数,必须起别名;
底层是字符串拼接,不是占位符,不安全,当#{}解决不了,就必须使用${};
可以使用,动态表名,动态列名,表达式运算等;
建议:MyBatis的SQL映射文件中,能优先使用#{},就必须使用,除非特殊情况,必须使用字符串拼接,才可以使用${};
使用动态表名查询动漫;
<!-- Anime selectProduceAndCid(@Param("produce") String produce,@Param("cid")Integer cid,@Param("tableName")String tableName); -->
<select id="selectProduceAndCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from ${tableName}
where `produce` = #{produce}
and `cid` = #{cid}
</select>
@Test
public void testMybatisMapperSelectParams5() throws IOException{
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
Anime anime = animeMapper.selectProduceAndCid("腾讯动漫", 2, "animes");
System.out.println(String.format("4.集合参数 根据动漫编号:%d,查询动漫详情%s",anime.getId(),anime));
}
查询多条数据, resultType 属性值还是实体类;
resultType="com.kgc.mybatis.bean.Anime"
Mybatis会自己走 返回集合的方法,自动将数据放到集合中;
//var1 select标签的id属性的值
<E> List<E> selectList(String var1);
//var2 为接口方法的参数
<E> List<E> selectList(String var1, Object var2);
//var3 为分页对象
<E> List<E> selectList(String var1, Object var2, RowBounds var3);
<!-- List<Anime> selectAnimeListByCid(Integer Cid); -->
<select id="selectAnimeListByCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `cid` = #{cid}
</select>
@Test
public void testMyBatisMapperSelectResults() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//根据动漫分类编号查询动漫
List<Anime> animeList = animeMapper.selectAnimeListByCid(3);
for (Anime anime : animeList) {
System.out.println(anime);
}
}
使用 #{} 建议使用 concat('%',#{name},'%');
使用 ${name} 必须给参数起别名;
<!-- List<Anime> selectAnimeListByName(String name); -->
<select id="selectAnimeListByName" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
<!-- where name like '%'#{name}'%'-->
where name like concat('%',#{name},'%')
</select>
<!-- List<Anime> selectAnimeListByName(@Param("name") String name); -->
<select id="selectAnimeListByName" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where name like '%${name}%'
</select>
使用${name} 如果不取别名, 取不到参数;
There is no getter for property named 'name' in 'class java.lang.String'
@Test
public void testMyBatisMapperSelectResults2() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//根据动漫名称 模糊 查询动漫列表
List<Anime> animeList = animeMapper.selectAnimeListByName("魁");
for (Anime anime : animeList) {
System.out.println(anime);
}
}
<select id="selectAnimeListByProduce" resultType="com.kgc.mybatis.bean.Anime">
<bind name="pageIndex" value="((pageNo - 1)*pageSize)"/>
select `id`,
`cid`
from `animes`
where `produce` like concat('',#{produce},'%')
<!-- 方式一:$符进行计算 -->
<!-- limit ${(pageNo - 1)*pageSize},#{pageSize} -->
<!-- 方式2:bind,自定义参数 -->
limit #{pageIndex},#{pageSize}
</select>
@Test
public void testSelectAnimeListByProduce() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//模拟获取分页参数
Integer pageNo = 1;
Integer pageSize = 3;
//调用mapper接口,模糊查询,查询分页列表
//方法一:调用接口的时候,计算好分页起始行,SQL中直接获取参数,实现分页
//方法二:使用 limit ${(pageNo - 1)*pageSize},#{pageSize}
//方法三:使用select的子标签bind,<bind name="pageIndex" value="((pageNo - 1)*pageSize)"/>
List<Anime> animeList = animeMapper.selectAnimeListByProduce("爱奇艺",pageNo,pageSize);
animeList.forEach(System.out::println);
}
Map<String,Object>,方法的返回类型是Map,key是String类型,value是Object类型,因为每个字段有不同的类型;
resultType="java.util.HashMap",因为将数据映射到map中;
<!-- Map<String,Object> selectAnimeMapById(Integer id); -->
<select id="selectAnimeMapById" resultType="java.util.HashMap">
select `id`,
`cid`,
`name`
from `animes`
where `id` = #{id}
</select>
@Test
public void testSelectAnimeByMapById() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
Map<String, Object> animeMap = animeMapper.selectAnimeMapById(301);
System.out.println(animeMap);
Object actor = animeMap.get("actor");
System.out.println("actor==>"+actor);
}
因为它不知道你要将哪个属性作为map的key值,所以需要@MapKey("id"),指定一个实体的属性作为map的key值;
//以动漫详情为例模拟返回map集合,将数据主键列值作为key,整条数据作为value
@MapKey("id") //这里的MapKey 是实体的一个属性
Map<Integer,Anime> selectAnimeMapByCid(Integer cid);
resultType="com.kgc.mybatis.bean.Anime",虽然返回的结果是map,但是数据是映射到Anime动漫实体中;
<!-- @MapKey("id") //这里的MapKey 是实体的一个属性 -->
<!-- Map<Integer,Anime> selectAnimeMapByCid(Integer cid); -->
<select id="selectAnimeMapByCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`
from `animes`
where `cid` = #{cid}
</select>
@Test
public void testSelectAnimeMapByCid() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
Map<Integer, Anime> animeMap = animeMapper.selectAnimeMapByCid(3);
System.out.println(animeMap);
Anime anime = animeMap.get(301);
System.out.println(anime);
}
| resultMap的参数 | 说明 |
|---|---|
| id | resultMap唯一id |
| type | 返回值类型 |
| autoMapping | 是否开启自动映射 |
resultMap自定义标签内指定的列才会映射,如果查询的结果列,不在自定义映射标签中,但是满足自动映射的条件(列名和实体属性名一致), 仍然会自动映射;
除非指定resultMap标签的autoMapping属性为false(autoMapping="false"),没有自定义映射的其他字段才不会自动映射;
<!-- Anime selectAnimeByResultMap(Integer id); -->
<select id="selectAnimeByResultMap" resultMap="animeResultMap">
select `id`,
`cid`,
`name`,
`author`,
`actor`,
`produce`,
`create_date` `crateTime`
from `animes`
where `id` = #{id}
</select>
<!--
autoMapping="false" 关闭自动映射,只使用自定义映射;
-->
<resultMap id="animeResultMap" type="com.kgc.mybatis.bean.Anime" autoMapping="false">
<!-- 主键映射标签 -->
<id column="id" property="id"></id>
<!-- 普通列映射标签 -->
<result column="cid" property="cid"></result>
<result column="name" property="name"></result>
<result column="crateTime" property="createDate"></result>
</resultMap>
@Test
public void testSelectAnimeByResultMap() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//使用自定义映射,查询动漫详情,解决列名和属性名不同意的映射
Anime anime = animeMapper.selectAnimeByResultMap(301);
System.out.println(anime);
}
实体属性,级联映射;
级联映射只适合一对一;
要求:查询动漫Anime,并且查询出动漫的 实体属性category 的信息;
一个动漫 对 一个动漫分类;
动漫实体Anime
public class Anime {
//动漫编号
private Integer id;
//分类编号
private Integer cid;
//名称
private String name;
......
//分类详情实体,一对一 (也可以定义分类名称冗余到实体中也可以解决)
private Category category;
}
分类实体Category
public class Category {
//分类编号
private Integer id;
//分类名称
private String name;
}
<result column="cid" property="category.id"></result>
| 参数 | 说明 |
|---|---|
| column="cid" | 连表查询出来的字段 |
| property="category.id" | 实体属性 的属性 |
先通过连表查询,将动漫信息和分类信息查询出来,再根据字段,一 一 映射;
<resultMap id="animeResultMapCascade" type="com.kgc.mybatis.bean.Anime" >
<!-- 主键映射标签 -->
<id column="id" property="id"></id>
<!-- 普通列映射标签 -->
<result column="cid" property="cid"></result>
<result column="name" property="name"></result>
<result column="author" property="author"></result>
<result column="create_date" property="createDate"></result>
<!-- 级联映射,通过 内部实体属性名.属性 -->
<result column="cid" property="category.id"></result>
<result column="cname" property="category.name"></result>
</resultMap>
@Test
public void testSelectAnimeByResultMapCascade() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//级联映射,动漫实体内部,分类实体属性的 级联映射
Anime anime = animeMapper.selectAnimeByResultMapCascade(301);
System.out.println(anime);
//Anime(id=301,
// cid=3,
// name=完美世界,
// ......
// category=Category(id=3, name=科幻)
// )
}
实体属性,关联映射;
要求:查询动漫Anime,并且查询出动漫的 实体属性category 的信息 ;
一个动漫 对 一个动漫分类;
动漫实体Anime
public class Anime {
//动漫编号
private Integer id;
//分类编号
private Integer cid;
//名称
private String name;
......
//分类详情实体,一对一
private Category category;
}
分类实体Category
public class Category {
//分类编号
private Integer id;
//分类名称
private String name;
}
先通过连表查询,查询出动漫信息,和动漫分类信息;
再通过association标签,对动漫的 实体属性 category 进行赋值;
<!-- Anime selectAnimeByResultMapAssociation(Integer id); -->
<select id="selectAnimeByResultMapAssociation" resultMap="animeResultMapAssociation">
select a.`id`,
a.`cid`,
a.`name`,
a.`author`,
a.`actor`,
a.`produce`,
a.`create_date`,
c.`name` 'cname'
from `animes` a,`category` c
where a.`cid` = c.`id`
and a.`id` = #{id}
</select>
<resultMap id="animeResultMapAssociation" type="com.kgc.mybatis.bean.Anime" >
<!-- 主键映射标签 -->
<id column="id" property="id"></id>
<!-- 普通列映射标签 -->
<result column="cid" property="cid"></result>
<result column="name" property="name"></result>
<result column="author" property="author"></result>
<result column="produce" property="produce"></result>
<result column="create_date" property="createDate"></result>
<!-- 关联映射,内部实体一对一 -->
<association property="category" javaType="com.kgc.mybatis.bean.Category">
<id column="cid" property="id"></id>
<result column="cname" property="name"></result>
</association>
</resultMap>
@Test
public void testSelectAnimeByResultMapAssociation() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
Anime anime = animeMapper.selectAnimeByResultMapAssociation(301);
System.out.println(anime);
//Anime(id=301,
// cid=3,
// name=完美世界,
// ......
// category=Category(id=3, name=科幻)
// )
}
要求:查询分类Category,并且查询出分类下的动漫集合属性 animes 信息;
一个动漫分类 对 多个动漫;
分类实体Category
public class Category {
//分类编号
private Integer id;
//分类名称
private String name;
//当前 分类下的 动漫集合
private List<Anime> animes;
}
动漫实体Anime
public class Anime {
//动漫编号
private Integer id;
//分类编号
private Integer cid;
//名称
private String name;
......
}
先通过连表查询,查询出动漫分类信息,和动漫信息;
再通过collection标签,对动漫分类的 集合属性 animes 进行赋值;
<!-- Category selectCategoryByResultMapCollection(Integer id); -->
<select id="selectCategoryByResultMapCollection" resultMap="categoryByResultMapCollection">
select c.`id`,
c.`name`,
a.`id` 'aid',
a.`cid`,
a.`name` 'aname',
a.`author`,
a.`actor`,
a.`create_date`,
a.`produce`
from `category` c,`animes` a
where c.`id` = a.`cid`
and c.`id` = #{id}
</select>
<resultMap id="categoryByResultMapCollection" type="com.kgc.mybatis.bean.Category">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!-- 高级映射,使用集合 关联映射,解决内部集合映射,一对多 -->
<collection property="animes" ofType="com.kgc.mybatis.bean.Anime">
<id column="aid" property="id"></id>
<result column="cid" property="cid"></result>
<result column="aname" property="name"></result>
<result column="author" property="author"></result>
<result column="actor" property="actor"></result>
<result column="produce" property="produce"></result>
<result column="create_date" property="createDate"></result>
</collection>
</resultMap>
@Test
public void testSelectCategoryByResultMapCollection() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
CategoryMapper categoryMapper = sqlSession.getMapper(CategoryMapper.class);
//查询动漫分类详情,内部集合类型 映射
Category category = categoryMapper.selectCategoryByResultMapCollection(3);
System.out.println(category);
//Category(id=3,
// name=科幻,
// animes=[Anime(id=301, cid=3, name=完美世界, ...),
// Anime(id=649, cid=3, name=蜡笔小新, ...)
// ]
// )
}
要求:查询动漫Anime,并且查询出动漫的 实体属性category 的信息 ;
一个动漫 对 一个动漫分类;
跟 关联映射 association 一对一 的实体一样;
<association property="category" select="com.kgc.mybatis.mapper.CategoryMapper.selectCategoryById" column="cid" fetchType="eager">
</association>
| 参数 | 说明 |
|---|---|
| property | 实体的属性 |
| select | 指定嵌套的select语句的唯一标识 |
| column | 指定嵌套的sleect语句执行需要的参数,多参数JSON格式 |
| fetchType | 是否适配系统延迟加载,默认是lazy,如果需要局部关闭延迟加载,改为eager |
先通过id查询动漫Anime,再通过动漫的cid,去查询 动漫分类;
AnimeMapper.xml
<!--Anime selectAnimeByResultMapAssociationLazyLoadingStep(Integer id);-->
<select id="selectAnimeByResultMapAssociationLazyLoadingStep" resultMap="associationLazyLoadingStep">
select `id`,
`cid`,
`name`,
`author`,
`actor`,
`produce`,
`create_date` `crateTime`
from `animes`
where `id` = #{id}
</select>
<!-- 嵌套select语句实现 延迟加载 和 分布查询 -->
<resultMap id="associationLazyLoadingStep" type="com.kgc.mybatis.bean.Anime">
<!-- 主键映射标签 -->
<id column="id" property="id"></id>
<!-- 普通列映射标签 -->
<result column="cid" property="cid"></result>
<result column="name" property="name"></result>
<result column="author" property="author"></result>
<result column="produce" property="produce"></result>
<result column="crateTime" property="createDate"></result>
<!-- 高级映射,内部实体一对一 ,嵌套select语句, 延迟加载和分布查询 -->
<!-- fetchType="eager" 局部覆盖按需加载 -->
<!--
select属性,指定嵌套的select语句的唯一标识(myabtis框架可识别的)
column属性:指定嵌套的sleect语句执行需要的参数,即将当前查询某列的值作为参数,传递到指定的查询语句中,如果有多个参数,可以使用JSON格式{key1=col1,key2=col2}
fetchType属性:设置当前自定高级映射是否适配系统延迟加载,默认是lazy,如果需要局部关闭延迟加载,改为eager
-->
<association property="category" select="com.kgc.mybatis.mapper.CategoryMapper.selectCategoryById" column="cid" fetchType="eager">
</association>
</resultMap>
CategoryMapper.xml
<!-- Category selectCategoryById(Integer id); -->
<select id="selectCategoryById" resultType="com.kgc.mybatis.bean.Category">
select `id`,
`name`
from `category`
where `id`= #{id}
</select>
@Test
public void testSelectAnimeByResultMapAssociationLazyLoadingStep() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
AnimeMapper animeMapper = sqlSession.getMapper(AnimeMapper.class);
//高级映射,内部实体一对一 ,使用嵌套select 延迟加载和分布查询
Anime anime = animeMapper.selectAnimeByResultMapAssociationLazyLoadingStep(301);
System.out.println("如果只使用动漫的信息,不使用加载 动漫分类的SQL");
System.out.println(anime.getName());
System.out.println("=============================================");
System.out.println("动漫的分类名称:"+anime.getCategory().getName());
}
开启延迟加载和按需加载

关闭延迟加载和按需加载,或者局部关闭延迟加载

要求:查询分类Category,并且查询出分类下的动漫集合属性 animes 信息;
一个动漫分类 对 多个动漫;
跟 关联映射 collection 一对多 的实体一样;
先通过id查询分类Category,再通过动漫的id,去查询cid等于id的动漫;
CategoryMapper.xml
<!--Category selectCategoryByResultMapCollectionAssociationLazyLoadingStep(Integer id); -->
<select id="selectCategoryByResultMapCollectionAssociationLazyLoadingStep" resultMap="associationLazyLoadingStep" >
select `id`,
`name`
from `category`
where `id`= #{id}
</select>
<resultMap id="associationLazyLoadingStep" type="com.kgc.mybatis.bean.Category">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!-- 高级映射,使用集合映射,解决内部 集合映射,一对多 -->
<collection property="animes" select="com.kgc.mybatis.mapper.AnimeMapper.selectAnimeListByCid" column="{cid=id}" fetchType="lazy">
</collection>
</resultMap>
AnimeMapper.xml
<!-- Map<Integer,Anime> selectAnimeMapByCid(Integer cid); -->
<select id="selectAnimeMapByCid" resultType="com.kgc.mybatis.bean.Anime">
select `id`,
`cid`,
`name`,
`author`,
`actor`,
`produce`,
`create_date`
from `animes`
where `cid` = #{cid}
</select>
@Test
public void testSelectCategoryByResultMapCollectionAssociationLazyLoadingStep() throws IOException {
SqlSession sqlSession = getSqlSessionFactory().openSession();
CategoryMapper categoryMapper = sqlSession.getMapper(CategoryMapper.class);
Category category = categoryMapper.selectCategoryByResultMapCollectionAssociationLazyLoadingStep(1);
System.out.println("分类名称:"+category.getName());
System.out.println("=============================================");
System.out.println("该分类下的动漫:"+category.getAnimes());
}
开启延迟加载和按需加载

关闭延迟加载和按需加载,或者局部关闭延迟加载

我有以下模型用户has_many:users_contactshas_many:contacts,through::users_contactsaccepts_nested_attributes_for:contacts,allow_destroy:true联系方式has_many:users_contactshas_many:users,through::users_contactsaccepts_nested_attributes_for:users_contacts,allow_destroy:true用户联系belongs_to:usersbelongs_to:contacts
我正在使用DataMapper,一个用于ruby的开源ORM,我很想抓挠。目前,DataMapper可以对一对多关系使用StrategicEagerLoading(SEL),但不能对发生N+1查询的多对多关系使用。我想设法让这项工作正常进行,但我找不到在哪里做。所以两部分问题:如何运行测试套件,以便它显示失败(注意,现在所有应该失败的规范都标记为待定)?在何处以及如何为一对多关系实现SEL? 最佳答案 对于第二个问题,您可以尝试深入研究代码:/lib/dm-core/associations/relationship.rb#Ea
我有以下内容:classUser'Car',:foreign_key=>'user_id'classCar'User',:foreign_key=>'user_id'它基本上是用户和汽车之间的一对一关系。我想要的是让用户能够拥有一辆且只有一辆汽车。这意味着如果他创造了一辆分配给他的汽车,他将无法创造第二辆。这是怎么做到的? 最佳答案 当然有几种不同的方法可以实现这一点。我建议在该表上创建一个复合键索引,以确保user_id在表中是唯一的。这将确保它只会出现一次。在迁移中,您可以这样写。add_index(:cars,:worker_
可以使用postgres数组在rails(4)中创建一对多/has_many关联吗?我知道外键类型数组是不可能的。示例:一项任务有多个受让人。传统上我会使用关联表来解决这个问题:tasks->assignees->users。使用数组,这将不是必需的,因为可以存储多个“外键”。然后可以使用以下查询来获取分配给我的所有任务:select*fromtaskswhere?INtasks.assignees 最佳答案 您将无法让Rails识别此数组并将其用于关联。但是如果您想要更快地搜索/过滤分配给用户的任务,您可以在任务对象中保留一个用户
我有两个模型,用户和组。每个组可以有多个用户,每个用户可以在多个组中。我目前有一些简单的东西,比如:用户:has_many:groups组:has_many:users所以我有一个groups_users表,它只是用group_id和user_id创建行。我想为此添加另一列(我有),问题是如何在不使用自定义SQL调用的情况下从模型访问它?在组模型中,我可以使用self.users,在用户中,我可以使用self.groups有没有办法从用户模型更改此表中的第三列?对不起,如果这令人困惑,请就此提出建议 最佳答案 这里有一些教程应该会有
我有一个字符串(例如“AABBCCDDEEFF”),我想将其拆分为一个数组,每个元素包含两个字符-["AA","BB","CC","DD","EE","FF"]. 最佳答案 试试String对象的scan方法:>>foo="AABBCCDDEEFF"=>"AABBCCDDEEFF">>foo.scan(/../)=>["AA","BB","CC","DD","EE","FF"] 关于ruby-将字符串拆分为Ruby中的一对字符,我们在StackOverflow上找到一个类似的问题:
我刚刚开始使用OOjavascript,所以请多多包涵。这个有效:varmyObj={foo:function(){alert('hello');this.bar();},bar:function(){alert('world');}}但是,如果我在“foo”方法中的hello警报之后做了一些其他事情,那么“this”的含义将从对象变为我上次选择的任何内容,因此使用this.bar()不执行类中的其他方法。所以我尝试将“this”缓存在一个变量中,如下所示:varmyObj={publicVars:{theObj:this},foo:function(){alert('hello');
我有两个具有一对多关系的Sequelize模型。我们称它们为所有者和属性(property)。假设它们是使用sails-hook-sequelize本身定义的(简化)。//Owner.jsmodule.exports={options:{tableName:'owner'},attributes:{id:{type:Sequelize.BIGINT,allowNull:false,primaryKey:true,autoIncrement:true},name:{type:Sequelize.STRING(255)},associations:function(){Owner.hasM
目前我正在使用jquerytablesorter和tablesorter过滤器。我的问题是我希望我的过滤器只过滤一列。现在它过滤所有列。你可以在这里看到我的网站:http://tinyurl.com/3j38vye现在它过滤所有列,我只想过滤“Lainasumma”列。您能否也说一下为什么它没有正确排序金额? 最佳答案 你看过documentation了吗??Hereisanexample如何禁用某些使用tablesorter的列。您可以传递一个headers对象,您可以在其中指定禁用哪些列。另一种方法是将class="{sorte
我有一个父子关系(一对多)。我能够创建child,但删除失败。我创建了一个child,保存它,但是当我删除时,我得到:Aforeignkeyvaluecannotbeinsertedbecauseacorrespondingprimarykeyvaluedoesnotexist.[Foreignkeyconstraintname=FK_dbo.Children_dbo.Parents_ParentId]我确实注意到,当删除被发送到服务器时,子项的parentid为0,实体状态为“已修改”。我希望这会被“删除”。相关View模型部分:functionqueryFailed(error){