注意顺序不能颠倒,否则启动时会发生异常。
MyBatis的映射器由一个接口加上XML映射文件组成,是最复杂的组件,映射文件常用元素如下:
下面先来看一下最常用的
示例(在mapper/UserDao.xml直接添加即可):
常用属性如下:
并修改UserDao,添加一个selectById方法:
UserselectById(Integerid);可以直接测试了:
@TestpublicvoidselectById(){System.out.println(dao.selectById(1));}下面来看一下如何传递多个参数。
有了最基本的select后,传递id这种单一参数很容易,但是实际情况中很多时候需要传递多个参数,MyBatis中传递多个参数有两种方式:
可以使用Map传递多个参数,示例
接着在UserDao下添加:
UserselectByMap(Map
@TestpublicvoidselectByMap(){Map
传递多个参数的另一种方法是利用JavaBean传递,创建一个POJO类:
@Getter@Setter@Builder@ToStringpublicclassUserPOJO{privateStringname;privateIntegerage;}修改UserDao接口方法:
publicUserselectByPOJO(UserPOJOuser)接着修改映射文件,实际上修改parameterType即可:
最后进行测试:
@TestpublicvoidselectByPOJO(){UserPOJOpojo=UserPOJO.builder().age(33).name("111").build();System.out.println(dao.selectByPOJO(pojo));}3.2
比如典型的主键回填
intinsertUser1(Useruser);一般来说插入操作返回一个整数,表示操作影响的行数,因此可以设置返回值为int,测试如下:
@TestpublicvoidinsertUser1(){Useruser=User.builder().age((short)88).name("test1").build();System.out.println(dao.insertUser1(user));System.out.println(user.getId());}另外如果不支持自增主键,可以使用selectKey自定义生成主键,比如:
测试:
@TestpublicvoidinsertUser2(){Useruser=User.builder().age((short)10).name("test2").build();System.out.println(dao.insertUser2(user));System.out.println(user.getId());}3.3
intupdateUser(Useruser);intdeleteUser(Integerid);测试:
@TestpublicvoidupdateUser(){Useruser=User.builder().id(3).name("3333333").age((short)11).build();selectAll();System.out.println(dao.updateUser(user));selectAll();}@TestpublicvoiddeleteUser(){selectAll();System.out.println(dao.deleteUser(3));selectAll();}3.4
List
@TestpublicvoidselectBySqlColumn(){System.out.println(dao.selectBySqlColumn());}4
示例的UserDao方法如下:
List
@TestpublicvoidselectReturnMap(){dao.selectReturnMap().forEach(System.out::println);}4.2使用POJO如果使用POJO存储返回的对象时,需要先定义一个POJO类,可以在上面的UserPOJO基础上加上一个id属性:
@Getter@Setter@Builder@ToStringpublicclassUserPOJO{privateIntegerid;privateStringname;privateIntegerage;}接着编写映射文件:
List
MyBatis支持一对一以及一对多级联,没有对多对多级联提供支持,但是可以用多个一对多级联实现多对多级联。下面分别来看一下。
一对一级联查询是最常见的级联查询,可以通过
下面通过一个例子进行说明,例子分五步:
为了方便新增表以及数据都写在一起:
usetest;droptableifexistsidcard;droptableifexistsperson;createtableidcard(idint(10)primarykeyauto_increment,codechar(18)collateutf8mb4_unicode_cidefaultnull);createtableperson(idint(10)primarykey,namevarchar(20)collateutf8mb4_unicode_cidefaultnull,agesmallintdefaultnull,idcard_idint(10)defaultnull,keyidcard_id(idcard_id),constraintidcard_idforeignkey(idcard_id)referencesidcard(id));insertintoidcard(`code`)values('123456789123456789');insertintoperson(`id`,`name`,`age`,`idcard_id`)values(1,'111',22,1);5.1.2实体类@DatapublicclassIdCard{privateIntegerid;privateStringcode;}@DatapublicclassPerson{privateIntegerid;privateStringname;privateIntegerage;privateIdCardcard;}另外还需要创建一个映射结果的POJO类:
@DatapublicclassPersonPOJO{privateIntegerid;privateStringname;privateShortage;privateStringcode;}5.1.3映射文件映射文件分为两个:
首先是IdCardMapper.xml,加上一个
接着在一个
最后再把结果整起起来,开启调试可以发现实际上也是执行了两条SQL:
而第二个
selectp.*,ic.codefrompersonp,idcardicwherep.idcard_id=ic.idandp.id=#{id}实际查询如下:
如果需要重要可以将其配置成
这个比较简单:
publicinterfacePersonDao{PersonselectPersonById1(Integerid);PersonselectPersonById2(Integerid);PersonPOJOselectPersonById3(Integerid);}5.1.5测试@TestpublicvoidselectPersonById(){System.out.println(dao.selectPersonById1(1));System.out.println(dao.selectPersonById2(1));System.out.println(dao.selectPersonById3(1));}注意在测试之前,需要修改配置文件mybatis-config.xml:
要注意的一个是
另外因为Dao接口没有加上@Mapper注解,因此需要在applicationContext.xml中手动加上Dao位置:
一对多的级联查询与一对一处理有相似之处,主要是映射文件中的
需要两张表:
user可以沿用前面的user表,而order表如下:
usetest;droptableifexistsorders;createtableorders(idint(10)primarykeyauto_increment,ordersnvarchar(10)collateutf8mb4_unicode_cidefaultnull,user_idint(10)defaultnull,keyuser_id(user_id),constraintuser_idforeignkey(user_id)referencesuser(id));insertintoorders(`ordersn`,`user_id`)values('testorder1',1),('testorder2',1),('testorder3',1);5.2.2实体类添加实体类Orders:
@DatapublicclassOrders{privateIntegerid;privateStringordersn;}同时创建一个带Orders的User:
@Data@Builder@NoArgsConstructor@AllArgsConstructorpublicclassUserWithOrders{privateIntegerid;privateStringname;privateShortage;privateList
首先是OrdersMapper.xml,只有一个简单的
第二个
publicinterfaceOrdersDao{List
下面同样通过五个步骤实现多对多级联。
需要订单表、商品表以及一个中间表,由于订单表Orders之前已创建,这里只需要创建两个表:
usetest;createtableproduct(idint(10)primarykeyauto_increment,namevarchar(10)collateutf8mb4_unicode_cidefaultnull,pricedoubledefaultnull);createtableorders_detail(idint(10)primarykeyauto_increment,orders_idint(10)defaultnull,product_idint(10)defaultnull,keyorders_id(orders_id),keyproduct_id(product_id),constraintorders_idforeignkey(orders_id)referencesorders(id),constraintproduct_idforeignkey(product_id)referencesproduct(id));insertintoproduct(`name`,`price`)values('product1',1.1),('product2',2.2),('product3',3.3);insertintoorders_detail(`orders_id`,`product_id`)values(1,1),(1,2),(1,3),(2,1),(2,3);5.3.2实体类订单类可以沿用之前的,只需要两个实体类:
publicinterfaceOrdersWithProductDao{List
(注这里用到了一个关键的1=1,仅作说明使用,实际开发请勿使用1=1进行拼接)
Dao接口:
List
@TestpublicvoidtestIf(){System.out.println(dao.selectByIf(User.builder().age((short)33).name("111").build()));}6.2
当其中一个
示例:
List
@TestpublicvoidtestChoose(){System.out.println(dao.selectByChoose(User.builder().age((short)33).build()));}6.3
这里是一个使用
List
@TestpublicvoidtestTrim(){System.out.println(dao.selectByTrim(User.builder().build()));System.out.println(dao.selectByTrim(User.builder().name("test2").build()));}6.4
List
@TestpublicvoidtestWhere(){System.out.println(dao.selectByWhere(User.builder().build()));System.out.println(dao.selectByWhere(User.builder().name("111").build()));System.out.println(dao.selectByWhere(User.builder().age((short)-3).build()));}6.5
intupdateBySet(Useruser);测试:
@TestpublicvoidtestSet(){System.out.println(dao.updateBySet(User.builder().name("999999").age((short)39).id(1).build()));System.out.println(dao.selectByWhere(User.builder().build()));}6.6
例子:
List
@TestpublicvoidtestForeach(){System.out.println(dao.selectByForeach(List.of(1,2,3)));}6.7
List
@TestpublicvoidtestBind(){System.out.println(dao.selectByBind(User.builder().name("test1").build()));}