mybatis学习—— mybatis 的参数深入 、输出结果封装、 SqlMapConfig.xml配置文件
parameterType 配置参数
1.1 使用说明
我们在上一章节中已经介绍了 SQL 语句传参,使用标签的 parameterType 属性来设定。该属性的取值可以 是基本类型,引用类型(例如:String 类型),还可以是实体类类型(POJO 类)。同时也可以使用实体类的包装 类,本章节将介绍如何使用实体类的包装类作为参数传递。
1.2 注意事项
基 本类 型和 String 我 们可 以直接 写类型 名称 ,也 可以 使用包 名 . 类名的 方式 ,例如 : java.lang.String。 实体类类型,目前我们只能使用全限定类名。 究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名, 而我们的是实体类并没有注册别名,所以必须写全限定类名。
这些都是支持的默认别名。
传递 pojo 包装对象
开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查 询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
2.1 编写 QueryVo
在domain包下定义QueryVo类:
public class QueryVo implements Serializable { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
2.2 在持久层接口中添加findByVo方法
/** * 根据QueryVo中的条件查询用户 */ List<User> findByVo(QueryVo vo);
2.3 持久层接口的映射文件
<!--根据用户名称模糊查询,参数变成一个QueryVo对象了--> <select id="findByVo" parameterType="com.churujianghudezai.domain.QueryVo" resultType="com.churujianghudezai.domain.User"> select * from user where username like #{user.username} </select>
2.4 测试包装类作为参数
@Test public void testFindByQueryVo(){ QueryVo vo = new QueryVo(); User user = new User(); user.setUsername("%王%"); vo.setUser(user); List<User> users = userDao.findByVo(vo); for (User u:users){ System.out.println(u); } }
resultType 配置结果类型
3.1 resultType 配置结果类型
resultType 属性可以指定结果集的类型,它支持基本类型和实体类类型。 我们在前面的 CRUD 案例中已经对此属性进行过应用了。 需要注意的是,它和 parameterType 一样,如果注册过类型别名的,可以直接使用别名。没有注册过的必须 使用全限定类名。例如:我们的实体类此时必须是全限定类名。
同时,在没有注册过实体类型别名的情况下,且返回结果为实体类时,实体类中的属性名称必须和查询语句中的列名保持一致,否则无法 实现封装。如下面代码:
User实体类:
public class User { private Integer id; private String name;//没有和数据库表中username一致 private Date birthday; private String sex; private String address; ....... ....... }
xml中对应的按名称查询的配置:(参数是string类型,所以uname也可写成name、username等都行,主要看重user类中name不与数据库列名username一致)
<!--根据名称模糊查询--> <select id="findByName" resultType="com.churujianghudezai.domain.User" parameterType="String"> select * from user where username like #{uname} </select>
test类中对应的测试方法:
@Test public void testFindByName(){ List<User> users = userDao.findByName("%王%"); for (User user:users){ System.out.println(user); } }
结果为:
如上可以发现:
在传递参数类型为基本数据类型或String时,参数名可以随意起,并且可以查询出数据,但因为结果类型为实体类,则类中名字与数据库表中列名不一致的属性将无法封装对应表中的值,故封装结果为null。
3.2 resultMap 结果类型
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。 在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
1. 修改实体类
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//实体类代码如下:(此时的实体类属性和数据库表的列名已经不一致了) public class User2 { private Integer userId; private String name; private Date userBirthday; private String Sex; private String userAddress; public Integer getUserId() { return userId; } public void setUserId(Integer userId) { this.userId = userId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getUserBirthday() { return userBirthday; } public void setUserBirthday(Date userBirthday) { this.userBirthday = userBirthday; } public String getSex() { return Sex; } public void setSex(String sex) { Sex = sex; } public String getUserAddress() { return userAddress; } public void setUserAddress(String userAddress) { this.userAddress = userAddress; } @Override public String toString() { return "User2{" + "userId=" + userId + ", name='" + name + '\'' + ", userBirthday=" + userBirthday + ", Sex='" + Sex + '\'' + ", userAddress='" + userAddress + '\'' + '}'; } }
2. 定义 resultMap,并配置映射
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<?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.churujianghudezai.dao.IUserDao"> <!--建立 User 实体和数据库表的对应关系 type 属性:指定实体类的全限定类名 id 属性:给定一个唯一标识,是给查询 select 标签引用用的--> <resultMap type="com.churujianghudezai.domain.User2" id="userMap"> <id column="id" property="userId"/> <result column="username" property="name"/> <result column="sex" property="Sex"/> <result column="address" property="userAddress"/> <result column="birthday" property="userBirthday"/> </resultMap> <!--id 标签:用于指定主键字段 result 标签:用于指定非主键字段 column 属性:用于指定数据库列名 property 属性:用于指定实体类属性名称 --> <!--这里的id值直接和接口里的方法名对应--> <!--根据id查询--> <select id="findById2" parameterType="int" resultMap="userMap"> select * from user where id = #{uid} </select> <!--保存用户--> <insert id="saveUser2" parameterType="com.churujianghudezai.domain.User2"> <!--配置时保存获取插入的id AFTER:此语句在插入语句之后执行 (可不写) keyColumn="id":keyColumn用于指定数据库表user中的主键(可不写) keyProperty="id": 此语句返回值要传递给当前方法参数中的id属性 (com.churujianghudezai.domain.User的id属性)(不可省) resultType=“int”: 此语句执行后的返回类型是 int keyProperty和resultType必不可少,且要相互对应才行--> <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER"> select last_insert_id(); </selectKey> insert into user(username,birthday,sex,address)values(#{name},#{userBirthday},#{Sex},#{userAddress}) </insert> <!--更新用户,这里以更新用户名为例--> <update id="updateUser2" parameterType="com.churujianghudezai.domain.User2"> update user set username=#{name} where id=#{userId} </update> <!--删除用户--> <delete id="deleteUser2" parameterType="int"> delete from user where id = #{id} </delete> <!--根据名称模糊查询--> <select id="findByName2" resultMap="userMap" parameterType="String"> select * from user where username like #{name}/* 此处也可以写成 like '%${value}%' */ </select> <!--查询总记录条数--> <select id="findTotal2" resultType="int"> select count(*) from user </select> <!--根据用户名称模糊查询,参数变成一个QueryVod对象了--> <select id="findByVo2" parameterType="com.churujianghudezai.domain.QueryVo" resultMap="userMap"> select * from user where username like #{user2.name} </select> </mapper>
3.定义Dao接口
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
User2 findById2(Integer uid); void saveUser2(User2 user); void updateUser2(User2 user); void deleteUser2(Integer uid); List<User2> findByName2(String username); int findTotal2(); List<User2> findByVo2(QueryVo vo);
4.在QueryVo类中添加属性user2
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
public class QueryVo implements Serializable { private User2 user2; public User2 getUser2() { return user2; } public void setUser2(User2 user2) { this.user2 = user2; } }
5.添加测试方法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
@Test public void testFindOne2(){ //6.执行操作 User2 user = userDao.findById2(41); System.out.println(user); } @Test public void testSaveUser2(){ User2 user = new User2(); user.setName("李小花"); user.setSex("女"); user.setUserBirthday(new Date()); user.setUserAddress("东北"); System.out.println("保存操作之前:"+user.getUserId()); userDao.saveUser2(user); //在dao操作完成后,直接调用getId()就可获得用户保存后对应的自增id System.out.println("保存操作完成,获得的id为"+user.getUserId()); } @Test public void testUpdateUser2(){ User2 user = userDao.findById2(52); user.setName("小飞侠"); userDao.updateUser2(user); user = userDao.findById2(52); System.out.println(user); } @Test public void testDeleteUser2(){ userDao.deleteUser2(55); } @Test public void testFindByName2(){ /*xml文件中使用%${value}%方式配置时,这里的参数只要写成 “王” 即可*/ List<User2> us = userDao.findByName2("%王%"); for (User2 user:us){ System.out.println(user); } } @Test public void testFindByQueryVo2(){ QueryVo vo = new QueryVo(); User2 user = new User2(); user.setName("%王%"); vo.setUser2(user); List<User2> users = userDao.findByVo2(vo); for (User2 u:users){ System.out.println(u); } }
以上过程添加、修改完成之后,即使库表中字段和实体类属性名不一致,也能实现返回结果的封装。
SqlMapConfig.xml配置文件
4.1 配置内容
SqlMapConfig.xml 中配置的内容和顺序
-properties(属性)
--property
-settings(全局配置参数)
--setting
-typeAliases(类型别名)
--typeAliase
--package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
--environment(环境子属性对象)
---transactionManager(事务管理)
---dataSource(数据源)
-mappers(映射器)
--mapper
--package
4.2 properties(属性)
在使用 properties 标签配置时,我们可以采用两种方式指定属性配置。
4.2.1 第一种方式
<properties> <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/> <property name="jdbc.url" value="jdbc:mysql://localhost:3306/ee05"/> <property name="jdbc.username" value="root"/> <property name="jdbc.password" value="123456"/> </properties> ..... <!--配置mybatis的环境--> <environments default="mysql"> <!--配置mybatis的环境--> <environment id="mysql"> <!--配置事务类型--> <transactionManager type="JDBC"></transactionManager> <!--配置连接数据库的信息,用的是数据源(连接池)--> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> .....
4.2.2 第二种方式
在 classpath 下定义 jdbcConfig.properties 文件:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ee05
jdbc.username=root
jdbc.password=123456
SqlMapConfig.xml写法如下:
<!-- 配置properties 可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息 resource属性: 常用的 用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。 url属性: 是要求按照Url的写法来写地址 URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。 它的写法: http://localhost:8080/mybatisserver/demo1Servlet 协议 主机 端口 URI URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。 --> <!--<properties resource="jdbcConfig.properties"></properties>--><!--这样写更简单些--> <properties url="file:///D:/IDEA/IdeaProjects/mybatis_studyCRUD/src/main/resources/jdbcConfig.properties"></properties> ...... <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> ......
4.3 typeAliases(类型别名)
在前面我们讲的 Mybatis 支持的默认别名,我们也可以采用自定义别名方式来开发。
4.3.1 自定义别名
在 SqlMapConfig.xml 中配置:
<!--使用typeAliases配置别名,它只能配置domain中类的别名 --> <typeAliases> <!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就不再区分大小写 <typeAlias type="com.churujianghudezai .domain.User" alias="user"></typeAlias>--> <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写--> <package name="com.churujianghudezai.domain"></package> </typeAliases>
IUserDao.xml里的参数类型就可以改成别名:
4.4 mappers(映射器)
<!--告知mybatis映射配置的位置--> <mappers> <!--<mapper resource="com/churujianghudezai/dao/IUserDao.xml"/> <mapper resource="com/churujianghudezai/dao/IUserDao2.xml"/>--> <!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class了 --> <!--注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中--> <!--该项目中,因为dao接口只有一个,而有两个xml文件(IUserDao.xml、IUserDao2.xml),因为接口和映射文件需要名称一一对应,所以IUserDao2.xml文件映射失败--> <package name="com.churujianghudezai.dao"/> </mappers>