在前面内容里,已经通过mybatis简单实现了一个查询功能,接下来主要通过XNL实现的方式,使用接口调用的方式,分别实现简单的CRUD的功能
mybatis XML方式
###1、select示例
以一个简单的用户权限控制为例,上面是权限控制对应表结构的ER图。在src/main/java下的tk.mybatis.simple.model包里新建对应的实体类。此处省略实体类的创建内容,五个类为SysUser,SysRole,sysPrivilege,SysUserRole,SysRolePrivilege在src/mian/resource下的tk.mybatis.simple.mapper包内新建 mapper对应的xml文件:UserMapper.xmL、RoleMapper.xml、PrivilegeMapper.xml 、UserRoleMapper.xml和
RolePrivilegeMapper.xml 同时在src/main/java下新建tk.mybatis.simple.mapper包,在包中新建XML文件对应的接口类:UserMapper.java、RoleMapper.java、PrivilegeMapper.java、UserRoleMapper.java、RolePrivilege.java接口类举例:
public interface UserMapper{}复制代码
xml文件举例:
复制代码
在使用接口进行方法调用的时候,mapper.xml中的namespace必须配置为接口类的全限定名称。
准备完对应的接口和XML文件后,在mybatis-config.xml配置文件的mappers元素中配置所有的mapper:复制代码
这里支持扫包的模式,扫包的时候会对配置的包下面的所以接口进行循环操作:
1、判读接口对应的命名空间是否存在,存在则抛出异常,不存在则继续操作2、加载接口对应的xml映射文件,通过接口的全路径名称加xml来查找并解析,这就是为什么xml文件名和接口名必须一致的原因3、处理接口中的方法在基本配置完成后,若要实现一个简单的查询功能,只要在xml文件中添加<select>
标签,写上sql语句,做一些简单配置把查询结果映射到对象中即可。
public interface UserMapper{ SysUser selectById(Long id);}复制代码
然后在对应的UserMapper.xml中添加如下的<resultMap>
和<select>
部分的代码:
复制代码
这里主要关注两点:
1、接口中的方法和XML通过<select>
标签的id属性进行关联,id的属性值和接口中的方法名是一致的,若方法名和id不一致就会报错。2、<select>
标签里的resultMap属性对应上面的<resultMap>
,这里是为了方便映射,做了详细配置,也可以参照前一篇内容中使用resultType属性,则无需进行额外配置,两者区别在于是否有具体的映射关系,有映射关系则可以使用select *
这样的查询操作,否则必须进行具体字段的查询,而且数据库字段必须和类字段一致,若不一致可以使用as
进行转换。具体的其他用法会在后面用到的地方具体描述。 ```是一种和重要的配置结果映射的方法
具体的使用可以参照Mybatis---resultMap部分的具体解析接口中定义的返回值类型必须和泊位中配置的resultType 类型一致,否则就会因为类型不一致而抛出异常。这里新增一个查询所有用户的方法,来区分不同返回值的情况,新增代码如下:
public interface UserMapper{ SysUser selectById(Long id); ListselectAll();}复制代码
#
select id, user_name userName, user_password userPassword, user_ema userEmail, user_info userInfo, head_img headImg, create_time createTime from sys_user 观察一下U serMapper.xmJ 中selectByid 和selectAll 的区别: selectByid 中使用了resultMap 来设置结果映射,而se lectAll 中则通过result Type 直接指定了返回结果的类型。可以发现,如果使用result Type 来设置返回结果的类型,需要在SQL 中为所有列名和属性名不一致的列设置别名,通过设置别名使最终的查询结果列和result Type 指定对象的属性名保持一致,进而实现自动映射。在数据库中,由于大多数数据库设置不区分大小写,因此下画线方式的命名很常见,如user_name、user_email 。在Java中,一般都使用驼峰式命名,如userName、userEmail。因为数据库和Java中的这两种命名方式很常见,因此MyBatis还提供了一个全局属性apUnderscoreToCamelCase,通过配置这个属性为true 可以自动将以下画线方式命名的数据库列映射到Java对象的驼峰式命名属性中。这个属性默认为false,如果想要使用该功能,需要在MyBatis的配置文件增加如下配置:
复制代码
使用该配置的时候,前面的selectAll方法就无需as
起别名。
测试:
为方便测试,编写一个基础测试类,用于初始化数据库连接:public class BaseMapperTest {private static SqlSessionFactory sqlSessionFactory;@BeforeClasspublic static void init(){ try { Reader reader = Resources.getResourceAsReader("mybatis-config.xml"); sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); reader.close(); }catch (Exception e){ e.printStackTrace(); }}public static SqlSession getSqlSessionFactory() { return sqlSessionFactory.openSession();}}复制代码
编写测试类XXXMapperTest继承基础测试类BaseMapperTest:
public class SysuserTest extends BaseMapperTest {@Testpublic void selectByIdTest(){ SqlSession sqlSession = getSqlSessionFactory(); try { UserMapper userMapper = sqlSession.getMapper(UserMapper.class); SysUser user = userMapper.selectById(1L); System.out.println("ID:"+user.getId()+"===name:"+user.getUserName()+"===password:"+user.getUserPassword()+ "===info:"+user.getUserInfo()+"===email:"+user.getUserEmail()+"===createtime:"+user.getCreateTime()); }catch (Exception e){ e.printStackTrace(); }finally { sqlSession.close(); }}@Testpublic void selectAllTest(){ SqlSession sqlSession = getSqlSessionFactory(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Listusers = userMapper.selectAll(); for(SysUser user : users ){ System.out.println("ID:"+user.getId()+"===name:"+user.getUserName()+"===password:"+user.getUserPassword()+ "===info:"+user.getUserInfo()+"===email:"+user.getUserEmail()+"===createtime:"+user.getCreateTime()); }}}复制代码
到这里,简单的select查询就结束了,复杂的查询主要区别在于sql已经和返回对象,在后面再详细描述。
###2、insert示例
在UserMapper中新增insert方法:int insert(SysUser sysUser);复制代码
在UserMapper.xml中新增insert标签
insert into sys_user( id,user_name,user_password,user_ema, user_info,head_img,create_time) values( #{id},#{userName},#{userPassword},#{userEmail}, #{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType = TIMESTAMP} ) 复制代码
看一下<insert>
元素的具体属性:
测试:
@Testpublic void insertTest(){ SysUser sysUser = new SysUser(); sysUser.setId(0000000000101L); sysUser.setUserName("testuser01"); sysUser.setUserPassword("test01"); sysUser.setUserEmail("test01@test.com"); sysUser.setUserInfo("he is test01 for test!"); sysUser.setHeadImg(null); sysUser.setCreateTime(new Date()); SqlSession sqlSession = getSqlSessionFactory(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Integer n = userMapper.insert(sysUser); //默认的sqlsession是不会自动提交的 sqlSession.commit(); System.out.println(n);}复制代码
一个简单的insert方法就实现了,注意在这里,方法的返回值是int类型的,这里的返回值是改变数据数据条数。
这里提供两个方法获取insert对象的主键:#####a、jdbc方式回显
新增一个insert2方法方便测试int insert2(SysUser sysUser);复制代码
在XML文件中配置insert2的sql如下:
insert into sys_user( user_name,user_password,user_ema, user_info,head_img,create_time) values( #{userName},#{userPassword},#{userEmail}, #{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType = TIMESTAMP} ) 复制代码
这里使用了useGeneratedKeys方法来获取自增的主键值,通过keyProperty属性把主键值付给id。
测试方法中insert2执行并commit后,获取sysuser对象的id发现回显了,带回了id的值#####b、使用selectkey方法获取id
新增一个insert3方法方便测试int insert3(SysUser sysUser);复制代码
在XML文件中配置insert3的sql如下:
insert into sys_user( user_name,user_password,user_ema, user_info,head_img,create_time) values( #{userName},#{userPassword},#{userEmail}, #{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType = TIMESTAMP} ) 复制代码select last_insert_id()
这里在<insert>
标签里面新增了一个<selectKey>
的标签,keyColumn、keyProperty和上面insert2方法中的用法一样,resultType是指定返回值对象,order是根据数据库类型指定,mysql使用‘AFTER’,因为主键值是insert语句执行完之后才能获取到,oracle使用‘BEFOR’,因为oracle数据库需要先从序列获取值,然后将值作为 主键插入到数据库中。
复制代码 select SEQ_ID.nextval from dual insert into sys_user( id,user_name,user_password,user_ema, user_info,head_img,create_time) values( #{id},#{userName},#{userPassword},#{userEmail}, #{userInfo},#{headImg,jdbcType=BLOB},#{createTime,jdbcType = TIMESTAMP} )
这里把<selectKey>
标签放到前面只是为了表示执行顺序,具体放在上面还是下面对代码没影响,决定执行顺序的是order字段的值。sql语句中明确写出了id是因为这里插入id的是根据查询出来的值再进行插入的,如果没有会报错。
###3、update示例
写一个根据主键更新数据的方法作为示例:在UserMapper接口中新增方法:int updateById(SysUser sysUser);
在UserMapper.xml中新增update标签: update sys_user set user_name=#{userName}, user_password=#{userPassword}, user_ema=#{userEmail}, user_info=#{userInfo}, head_img=#{headImg,jdbcType=BLOB}, create_time=#{createTime,jdbcType=TIMESTAMP} where id=#{id} 复制代码
测试:
@Testpublic void updateByIdTest(){ SysUser sysUser = new SysUser(); sysUser.setId(1001L); sysUser.setUserName("testuser05_update"); sysUser.setUserPassword("test05_update"); sysUser.setUserEmail("test05_update@test.com"); sysUser.setUserInfo("he is test05_update for test!"); sysUser.setHeadImg(null); sysUser.setCreateTime(new Date()); SqlSession sqlSession = getSqlSessionFactory(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Integer n = userMapper.updateById(sysUser); //默认的sqlsession是不会自动提交的 sqlSession.commit(); System.out.println(sysUser.getId()); System.out.println(n);}复制代码
###4、delete示例
写一个根据id删除数据的方法作为示例:在UserMapper接口里新增一个删除方法:int deleteById(Long id);
在UserMapper.xml中新增对应的delete标签: delete from sys_user where id=#{id} 复制代码
测试:
@Testpublic void deleteById(){ SqlSession sqlSession = getSqlSessionFactory(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Integer n = userMapper.deleteById(1005L); //默认的sqlsession是不会自动提交的 sqlSession.commit(); System.out.println(n);}复制代码
当然这里如果传参传User对象也是可以的,xml文件中不需要修改,直接修改接口参数为User对象就行。
###5、多个参数作为方法参数时的处理
如果要执行的CRUD方法有多个参数的时候应该如何处理?一般有两种方法:1、新建一个map对象:把多个参数通过key和value传进去,但是这种方式要自己新建map对象,一般不推荐。2、使用@Param
注解的方式:例:根据用户ID和角色的enabled状态获取角色对象List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId")Long userId,@Param("enabled")Integer enabled);
在xml中使用如下: 复制代码
若要传入的不是基本类型而是javaBean对象也是可以的,对应的则使用.
的方式来获取:
List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("user")SysUser sysUser,@Param("role")SysRole sysRole);
xml中则使用where u.id=#{user.id) and r.enabled=#{role.enabled)
从javaBean对象中获取对应的值。