SQL的映射文件
使用MyBatis 实现条件查询
SQL映射文件
mapper:映射文件的根元素节点,只有一个属性namespace(命名空间),其作用如下:
- 用于区分不同的mapper,全局唯一
- 绑定DAO接口,即面向接口编程,当namespace绑定某一接口之后,可以不用写该接口的实现类, MyBatis会通过接口的完全限定名查找到对应的mapper配置来执行SQL语句,因此namespace的命名必须要跟接口同名
cache:配置给定命名空间的缓存
cache-ref:从其他命名空间引用缓存配置
resultMap:用来描述数据库结果集和对象的对应关系
sql:可以重用的SQL块,也可以被其他语句引用
insert:映射插入语句
update:映射更新语句
delete:映射删除语句
select:映射查询语句
注意:在不同的Mapper文件中,子元素的id可以相同,Mybatis通过namespace和子元素的id联合区分,接口中的方法与映射文件中SQL语句id应一一对应
使用select完成单条件查询
<!--根据用户名查询用户列表(模糊查询)-->
<select id="getUserListByUserName" resultType="User" parameterType="string">
SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%')
</select>
各属性介绍:
id:命名空间中唯一的标识符,可以被用来引用这条语句
parameterType:表示查询语句传入参数的类型的完全限定名或别名。
resultType:查询语句返回结果类型的完全限定名或别名别名表
使用select完成多条件查询
编写接口
public interface UserMapper{
//查询用户列表(参数:对象入参)
List<User> getUserListByUser(User user);
}
编写映射文件
<select id="getUserListByUser" resultType="User" parameterType="User">
SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%') and userRole=#{userRole}
</select>
编写测试
public void testGetUserList(){
SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>();
try{
sqlSession=MyBatisUtil.createSqlSession();
User user=new User();
user.setUserName("王");
user.setUserRole(3);
userList=sqlSession.getMapper(UserMapper.class).getUserListByUser(user);
}catch (Exception ex){
ex.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User user: userList) {
System.out.println("userName:"+user.getUserName()+"\t"+"userRole:"+user.getUserRole());
}
}
当然也可以用别的方式入参,大家可以多试一试,都是大同小异的
使用resultMap完成查询结果的展示
resultMap的意思就是我们数据库的字段和我们实体类中的属性不一致的时候或者我们做一些复杂的查询,需要使用到resultMap 比如:我们有一个用户类,这里面有一个角色id 但是没有角色的名字,但是我们想要查这个角色的名字,这个时候我们就可以用到resultMap,具体操作请看下面示例
首先现在User(用户)类中加入角色名字这个属性
private String roleName;//角色名称
//省略getter和setter
编写UserMapper.xml文件,修改其中的getUserList方法
<select id="getUserList" resultMap="userList" parameterType="User">
SELECT u.*,r.roleName FROM USER u,Role r WHERE u.userName LIKE concat('%',#{userName},'%')
AND u.userRole=#{userRole} AND u.userRole=r.id
</select>
添加id为userList的resultMap元素节点
<resultMap id="userList" type="User">
<result property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<result property="phone" column="phone"/>
<result property="birthday" column="birthday"/>
<result property="gender" column="gender"/>
<result property="userRole" column="userRole"/>
<result property="userRoleName" column="roleName"/>
</resultMap>
编写测试
public void testGetUserList(){
SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>();
try{
sqlSession=MyBatisUtil.createSqlSession();
User user=new User();
user.setUserName("王");
user.setUserRole(3);
userList=sqlSession.getMapper(UserMapper.class).getUserList(user);
}catch (Exception ex){
ex.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
for (User user: userList) {
System.out.println(user.getUserName()+"\t"+user.getUserRole()+"\t"+user.getUserRoleName());
}
}
resultMap元素的属性值和子节点:
id属性:唯一标识,此id值用于select元素resultMap属性的引用
type属性:表示该resultMap的映射结果类型
result子节点:用于标识一些简答的属性,其中column属性表示从数据库中查询的字段名,property则表示查询出来的字段对应的赋值给实体对象的哪个属性
resultType和resultMap的异同点及场景
1.resultType直接表示返回类型,包括基本数据类型和复杂数据类型
2.resultMap则是对外部resultMap定义的引用,对应外部resultMap的id
3.MyBatis的每个查询映射的返回类型都是resultMap,当我们提供的返回类型是resultType,会自动赋值给指定属性
4.resultMap自动映射界别默认映射级别为PARTIAL,在resultMap没有做映射关联时也能自动匹配。
当然也可以把自动匹配关掉
<settings>
<!--设置resultMap的自动映射级别为NONE(禁止自动匹配)-->
<setting name="autoMappingBehavior" value="NONE"/>
</settings>
使用Mybatis实现增删改查操作
使用insert完成增加操作
在接口中添加add()方法
public int add(User user);
在映射文件中编写插入语句
<insert id="add" parameterType="User">
INSERT INTO USER (userCode,userName,userPassword,gender,birthday,
phone,address,userRole,createdBy,creationDate)
VALUES (#{userCode},#{userName},#{userPassword},#{gender},#{birthday},
#{phone},#{address},#{userRole},#{createdBy},#{creationDate})
</insert>
insert元素中属性的意思和select一样
编写测试类
public void testAdd(){
SqlSession sqlSession=null;
try{
sqlSession=MyBatisUtil.createSqlSession();
User user=new User();
user.setUserCode("test");
user.setUserName("测试数据");
user.setUserPassword("anxin123");
user.setGender(1);
Date birthday=new SimpleDateFormat("yyyy-MM-dd").parse("1990-1-1"); user.setBirthday(birthday);
user.setPhone("1228392324");
user.setAddress("北京");
user.setUserRole(3);
user.setCreatedBy(1);
user.setCreationDate(new Date());
int count=sqlSession.getMapper(UserMapper.class).add(user);
System.out.println("数量:"+count);
sqlSession.commit();
}catch (Exception ex){
ex.printStackTrace();
sqlSession.rollback();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
使用update完成修改
在接口中添加modify()方法
public int modify(User user);
在映射文件中编写修改语句
<update id="modify" parameterType="User">
UPDATE USER SET userCode=#{userCode},userName=#{userName},userPassword=# {userPassword},
gender=#{gender},phone=#{phone},address=#{address},userRole=#{userRole},modifyBy=# {modifyBy},
modifyDate=#{modifyDate},birthday=#{birthday}
WHERE id=#{id}
</update>
编写测试代码
public int modify(){
SqlSession sqlSession=null;
try{
sqlSession=MyBatisUtil.createSqlSession();
User user=new User();
user.setId(15);
user.setUserCode("test1");
user.setUserName("测试皮皮修改");
user.setUserPassword("mengqingpi123");
user.setGender(1);
Date birthday=new SimpleDateFormat("yyyy-MM-dd").parse("1990-1-1");
user.setBirthday(birthday);
user.setPhone("1228392324");
user.setAddress("北京");
user.setUserRole(3);
user.setCreateBy(1);
user.setCreationDate(new Date());
int count=sqlSession.getMapper(UserMapper.class).modify(user);
//int i=2/0;//测试事务回滚
System.out.println("数量:"+count);
sqlSession.commit();//事务提交
}catch (Exception ex){
ex.printStackTrace();
sqlSession.rollback();//事务回滚
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
使用@Param注解实现多参数入参
如果我们只有两个或者三个参数没有必要封装成对象,我们可以直接多参数入参,这样代码可读性会更高
比如我们要修改密码 在参数前增加@Param注解
public int updatePwd(@Param("id")Integer id,@Param("userPassword")String pwd);
上面代码中的@Param("userPassword")String pwd 就相当于把参数pwd改名为userPassword,在映射的SQl中需要使用#{注解名称}
编写修改的SQL语句
<update id="updatePwd">
UPDATE USER SET userPassword=#{userPassword} WHERE id=#{id}
</update>
编写测试类
public void testUpdatepwd(){
SqlSession sqlSession=null;
try{
sqlSession=MyBatisUtil.createSqlSession();
int id=15;
String pwd="pipi456";
int count=sqlSession.getMapper(UserMapper.class).updatePwd(id,pwd);
//int i=2/0;//测试事务回滚
System.out.println("数量:"+count);
sqlSession.commit();
}catch (Exception ex){
ex.printStackTrace();
sqlSession.rollback();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
经验:超过4个参数最好封装成对象入参(特别是在常规增加或者修改时,字段较多,封装成对象比较方便)
使用delete完成删除操作
编写接口方法
public int deleteUserById(@Param("id")Integer delId);
在映射文件中编写删除的SQL语句
<delete id="deleteUserById">
DELETE FROM USER WHERE id=#{id}
</delete>
编写测试
public void testDeleteUser(){
SqlSession sqlSession=null;
try{
sqlSession=MyBatisUtil.createSqlSession();
int id=15;
int count=sqlSession.getMapper(UserMapper.class).deleteUserById(id);
System.out.println("数量:"+count);
sqlSession.commit();
}catch (Exception ex){
ex.printStackTrace();
sqlSession.rollback();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
使用resultMap实现高级结果映射(表表关联)
association:映射到JavaBean的某个“复杂查询”属性,比如javaBean类,即JavaBean内部嵌套一个复杂数据类型,这种情况就属于复杂类型的关联,但是要注意:association只处理一对一的关系
在这里我们用用户的角色做演示,因为一个用户只有一个角色(角色的意思 比如:管理员,站长)
Role类(角色)
public class Role {
private Integer id;
private String roleCode;
private String roleName;
private Integer createdBy;
private Date creationDate;
private Integer modifyBy;
private Date modifyDate;
//省略getter和setter
}
修改User类,添加角色属性(Role)
public class User {
private Integer id;//id
private String userCode;//用户编码
private String userName;//用户名称
private String userPassword;//用户密码
private Integer gender;//性别
private Date birthday;//出生日期
private String phone; //电话
private String address;//地址
private Integer userRole;//用户角色
private Integer createdBy;//创建者
private Date creationDate;//创建时间
private Integer modifyBy;//更新者
private Date modifyDate;//更新时间
//private String userRoleName;//用户角色名称
private Role role;
//省略getter&setter方法
}
在UserMapper接口中添加方法
public List<User> getUserListByRoleId(@Param("userRole")Integer roleId);
修改UserMapper.xml
<resultMap id="userRoleResult" type="User">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<result property="userRole" column="userRole"/>
<association property="role" javaType="Role">
<id property="id" column="r_id"/>
<result property="roleCode" column="roleCode"/>
<result property="roleName" column="roleName"/>
</association>
</resultMap>
<select id="getUserListByRoleId" parameterType="Integer" resultMap="userRoleResult">
SELECT u.*,r.id AS r_id,r.roleCode,r.roleName
FROM user u,role r
WHERE u.userRole=#{userRole} and u.userRole=r.id
</select>
如果我们每次都要查询关联数据的话,每次都要写association这个节点,比较麻烦,我们可以用resultMap 复用配置
<resultMap id="roleResult" type="Role">
<id property="id" column="r_id"/>
<result property="roleCode" column="roleCode"/>
<result property="roleName" column="roleName"/>
</resultMap>
<resultMap id="userRoleResult" type="User">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<result property="userRole" column="userRole"/>
<association property="role" javaType="Role" resultMap="roleResult"/>
</resultMap>
编写测试类:
public void getUserListByRoleIdTest(){
SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>();
Integer roleId=3;
try{
sqlSession=MyBatisUtil.createSqlSession();
userList=sqlSession.getMapper(UserMapper.class).getUserListByRoleId(roleid);
}catch (Exception ex){
ex.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
for(User user:userList){
System.out.print("userList--->userName:"+user.getUserName()
+",Role:"+user.getRole.getId()
+"----"+user.getRole.getRoleCode()
+"----"+user.getRole().getRoleName());
}
}
collection:collection元素的作用和association元素的作用差不多,事实上他们非常类似,也是映射到JavaBean的某个“复杂类型”属性,只不过这个属性是一个集合列表即JavaBean内部嵌套一个复杂数据类型(集合)属性,和使用association元素一样,我们使用嵌套查询,或者从连接中嵌套结果集
collection处理的是 一对多的关联
在这里我们还是用用户举例 我们每个用户有很多地址,就像我们淘宝购物一样有不同的地址,所以说我们和地址是一对多的关系
创建Address类(地址)
public class Address {
private Integer id;
private String contact;
private String addressDesc;
private String postCode;
private String tel;
private Integer createdBy;
private Date creationDate;
private Integer modifyBy;
private Date modifyDate;
private Integer userId;
//省略getter和setter
}
修改User类添加地址属性
public class User {
private Integer id;//id
private String userCode;//用户编码
private String userName;//用户名称
private String userPassword;//用户密码
private Integer gender;//性别
private Date birthday;//出生日期
private String phone; //电话
private String address;//地址
private Integer userRole;//用户角色
private Integer createdBy;//创建者
private Date creationDate;//创建时间
private Integer modifyBy;//更新者
private Date modifyDate;//更新时间
//private String userRoleName;//用户角色名称
private Role role;
private List<Address> addressList();//用户地址列表
//省略getter&setter方法
}
编写接口中的方法
public List<User> getAddressListByUserId(@Param("id")Integer userId);
编写映射文件
<resultMap id="addressResult" type="Address">
<id column="a_id" property="id"/>
<result property="postCode" column="postCode"/>
<result property="tel" column="tel"/>
<result property="contact" column="contact"/>
<result property="addressDesc" column="addressDesc"/>
</resultMap>
<resultMap id="userAddressResult" type="User">
<id property="id" column="id"/>
<result property="userCode" column="userCode"/>
<result property="userName" column="userName"/>
<collection property="addressList" ofType="Address" resultMap="addressResult"/>
</resultMap>
<select id="getAddressListByUserId" parameterType="Integer" resultMap="userAddressResult">
select u.*,a.id as a_id,a.contact,a.addressDesc,a.postCode,a.tel
from smbms_user u LEET JOIN smbms_address a ON u.id=a.userId
where u.id=#{id}
</select>
编写测试方法
public void getAddressListByUserIdTest(){
SqlSession sqlSession=null;
try{
sqlSession=MyBatisUtil.createSqlSession();
List<User> userList=sqlSession.getMapper(UserMapper.class).getAddressListByUserId(1);
for (User user: userList) {
System.out.println(user.getUserName());
List<Address> addresses=user.getAddressList();
for (Address address: addresses) {
System.out.println("--- "+address.getContact());
}
}
}catch (Exception ex){
ex.printStackTrace();
}finally {
MyBatisUtil.closeSqlSession(sqlSession);
}
}
resultMap自动映射级别
autoMappingBehavior的三个级别
NONE:禁止自动匹配
PARTIAL:(默认)自动匹配所有属性,有内部嵌套(assocition,collection)除外
FULL:自动匹配所有
<settings>
<setting name="autoMappingBehavior" value="Full"/>
</settings>
可能有很多东西讲的不是很清晰,希望大家可以留言讨论
by 安心