MyBatis框架基于XML配置文件开发
本文内容涉及MyBatis框架开发的传参,多表查询,结果封装;
说明:
当前使用的是mysql数据库,
测试在maven工程下;
数据库表:
book表:
kind表:
表关系:
JavaBean如下:
//主表
public class Kind {
private Integer kid;
private String kname;
private List<Book> books;
...get/set方法省略
//从表
public class Book {
private Integer id;
private String bookName;
private String author;
private String company;
private Double price;
private Integer kid;
private Kind kind;
...get/set方法省略
场景一:要查询数据有 bookname,author,price, 还有 三本书的价格
分析:bookname,author,price 这三个字段,Book实体已经有对应的属性了;而3*price Book实体里没有对应的属性,MyBatis就不能帮我们自动封装数据了,怎么解决这个问题呢?
方法一:创建实体子类
我们的目的就是为了找个属性去封装数据,那么我们可以再加一个属性(当然不能在book实体上面加),我们可以再写一个实体,去继承现有的实体类,那么我们最后得到这个实体类有它父类的所有属性并且我们可以想加什么就加什么属性了;下面看代码:
public class BookVo extends Book {
private Double total;
...get/set方法省略
}
BookMapper接口,方法;
List<BookVo> findAll();
BookMapper.xml配置文件;
<select id="findAll" resultType="BookVo">
select bookname,author,price,3*price as total from book
</select>
数据封装图解:
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
List<BookVo> all = bm.findAll();
for (BookVo bookVo : all) {
System.out.println("bookname:"+bookVo.getBookName());
System.out.println("author:"+bookVo.getAuthor());
System.out.println("price:"+bookVo.getPrice());
System.out.println("3*price:"+bookVo.getTotal());
}
}
打印结果:
bookname:从稚气小孩到科学巨人
author:松鹰
price:189.5
3*price:568.5
....
方法二:封装到Map
BookMapper接口,方法;
List<Map> findAll2();
BookMapper.xml配置文件;
<select id="findAll2" resultType="Map">
select bookname,author,price,3*price as total from book
</select>
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
List<Map> all2 = bm.findAll2();
for (Map map : all2) {
System.out.println("bookname:"+map.get("bookname"));
System.out.println("author:"+map.get("author"));
System.out.println("price:"+map.get("price"));
System.out.println("3*price:"+map.get("total"));
}
}
DeBug:
测试代码调用查询方法返回List集合,List集合里面存的是HashMap,HashMap里以键值对的方式存着从数据库里查出来的数据;这个可以来多少存多少,不用考虑实体有没有对应的数据,无脑存就行了。但是这种方法的效率相对上一种方法的效率较低。
打印结果:
bookname:从稚气小孩到科学巨人
author:松鹰
price:189.5
3*price:568.5
.....
场景二:查询价格在100到300之间的书籍信息(传参问题,标签问题)
先上代码:
BookMapper接口,方法;
List<Book> findByPrice(double a,double b);
BookMapper.xml配置文件;
<select id="findByPrice" resultType="Book">
select * from book where price > #{a} and price < #{b}
</select>
能向上面这样写吗? 答案肯定是否定的;
先不说参数传递的问题,sql语句在配置文件里写的时候就已经报错了;
原因就是程序会认为 ‘ < ’这个符号是标签的开始,然后就直接报错;
解决方法就是 把程序容易误解的代码用< ![CDATA[]] > 标签包裹起来,如下:
<select id="findByPrice" resultType="Book">
select * from book where price > #{a} and price <![CDATA[ < #{b} ]]>
</select>
现在就没问题了吗? 这么说就是有问题喽
这里调用方法传参过来并没有一个 a 对应 a ,b 对应 b的关系;所以仍然会报错;
下面给出三个正确传参的写法:
写法一:
List<Book> findByPrice(@Param("a") double a, @Param("b") double b);
<select id="findByPrice" resultType="Book">
select * from book where price > #{a} and price <![CDATA[ < #{b} ]]>
</select>
写法二:
List<Book> findByPrice(double a,double b);
<select id="findByPrice" resultType="Book">
select * from book where price >#{param1} and price <![CDATA[ < #{param2} ]]>
</select>
写法三:
List<Book> findByPrice(double a,double b);
select * from book where price >#{arg0} and price <![CDATA[ < #{arg1} ]]>
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
List<Book> byPrice = bm.findByPrice(100d, 300d);
for (Book book : byPrice) {
System.out.println(book);
}
}
打印结果:
Book{id=4, bookName='从稚气小孩到科学巨人', author='松鹰', company='人民邮电出版社', price=189.5, kid=null}
....
场景三:查询book 表 bookname,author,kind表 kname(多表查询)
分析:这个查询是多对一 我们需要kind查询到的结果封装到 book实体
方法一:
BookMapper接口,方法;
List<Book> findBook();
BookMapper.xml配置文件;
<resultMap id="map1" type="Book">
<result column="kname" property="kind.kname"/>
</resultMap>
<select id="findBook" resultMap="map1">
select bookname,author,kname from book b,kind k where b.kind_id = k.kid
</select>
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
List<Book> book = bm.findBook();
for (Book book1 : book) {
System.out.println("书名:"+book1.getBookName());
System.out.println("作者:"+book1.getAuthor());
System.out.println("类别:"+book1.getKind().getKname());
}
}
打印结果:
书名:从稚气小孩到科学巨人
作者:松鹰
类别:网络文学类
....
方法二:
这个方法需要创建KindMapper接口,KindMapper.xml配置文件
KindMapper接口
public interface KindMapper {
Kind findById(int id);
}
KindMapper.xml配置文件
<select id="findById" resultType="kind">
select * from kind where kid=#{id}
</select>
BookMapper接口,方法;
public interface BookMapper {
List<Book> findBook2();
}
BookMapper.xml配置文件
<resultMap id="map2" type="Book">
<association column="kind_id" property="kind" select="top.cloudhui.mapper.KindMapper.findById"></association>
</resultMap>
<select id="findBook2" resultMap="map2">
select * from book
</select>
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
List<Book> book2 = bm.findBook2();
for (Book book : book2) {
System.out.println("书名:"+book.getBookName());
System.out.println("作者:"+book.getAuthor());
System.out.println("类别:"+book.getKind().getKname());
}
}
打印结果:
书名:从稚气小孩到科学巨人
作者:松鹰
类别:网络文学类
....
这个方法也是使用resultMap去封装数据,但是使用了association标签,根据关联的字段联合了一个方法查询kind表并封装数据;
场景四:查询book表,kind表,列出相同类别的数名(一对多)
先上代码:
KindMapper接口
public interface KindMapper {
List<Kind> findBook();
}
KindMapper.xml配置文件
<resultMap id="map1" type="kind">
<result column="kname" property="kname"/>
<collection property="books" ofType="Book">
<result column="bookname" property="bookName"/>
</collection>
</resultMap>
<select id="findBook" resultMap="map1">
select bookname,kname from book b,kind k where b.kind_id = k.kid
</select>
测试代码:
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
BookMapper bm = ac.getBean("bookMapper", BookMapper.class);
KindMapper km = ac.getBean("kindMapper", KindMapper.class);
List<Kind> book = km.findBook();
for (Kind kind : book) {
System.out.println("["+kind.getKname()+"]");
List<Book> books = kind.getBooks();
for (Book book1 : books) {
System.out.println(book1.getBookName());
}
}
}
打印结果:
[网络文学类]
内向性格的竞争力
熊镇
有话说
从稚气小孩到科学巨人
知更鸟女孩
......
[计算机类]
Ajax与jQuery程序设计
Java编程思想
编程风格
分布式服务框架原理与实践
SpringBoot揭秘