[Spring MVC3]MyBatis详解

本章重点讲述了MyBatis映射器,对数据层进行的操作,建议本篇文章和Spring Boot的持久层相互比较来看会更加收获颇多Spring Boot持久层技术

本文需要使用到MVC第一讲的模板格式与配置情况,全部代码已经放在此博客中,Spring MVC1

MyBatis映射器

映射器主要元素

元素描述
select映射查询
insert映射插入
update映射更新
delete映射删除
sql可以被其他语句引用的可重用语句块
resultMap描述层数据库结果集加载对象
cache缓存配置
cache-ref缓存配置的引用

注意MyBatis的配置我是在AyUserMapper.xml进行配置,所定位的Dao层如下图查看,通过mapper标签对dao接口进行一对一的映射,这是相对复杂的xml配置,后面会讲到注解的方式
在这里插入图片描述
同时在applicationContext.xml进行扫描:
在这里插入图片描述

select 元素

可以从数据库读取数据,组装数据给业务人员。比如在AyUserMapper.xml使用select元素,根据id查找(相关文件与建表命令在Spring MVC1列出)
AyUserMapper.xml

<select id="findById" parameterType="String" resultType="com.ay.model.AyUser">
        select * from ay_user where id = #{id}
    </select>

这个语句就是findById,接收一个String类型的参数,并返回一个User.#{id}就是预处理语句,类似于:

String findById = "select * from ay_user where id = ?";
PreparedStatement ps = conn.prepareStatement(findById);
ps.setString(1,id);

在接口AyUserDao,AyUserService写下此方法:

AyUser findById(String id);

在AyUserServiceImpl:

public AyUser findById(String id) {
        return ayUserDao.findById(id);
    }

下面进入到控制层进行测试:AyUserController:

@GetMapping("/findById")
    public String findById(Model model) {
        AyUser m = null;
        m=ayUserService.findById("1");
        System.out.println(m.getName()+"AAA");
        return "hello";
    }

运行,浏览器输入80/user/findById,可以在控制台看到相应的信息
在这里插入图片描述
xml中的select id注意要和DAO接口的方法名要一致,否则不一致会抛出异常。
resultType:从语句返回期望类型的类完全限定类名;

下面再来看几个例子:

<select id="countByName" parameterType="String" resultType="int">
        select count(*) from ay_user
    </select>

对于的AyUserDao如下:

int countByName(String name);

insert 元素

用来映射DML语句,MyBatis会在执行插入后返回一个整数,来表示操作后的记录数。
下面的属性如下:

属性描述
useGeneratedKeys令MyBatis使用JDBC来获取数据库的主键
keyColumn指明第几列为主键,不与keyProperty公用
keyProperty指明哪个列作为主键
下面来看几个例子:
<insert id="insertUserTest" parameterType="com.ay.model.AyUser">
        insert into ay_user(id,name,password) values(#{id},#{name},#{password});
    </insert>
//或者使用主键自增的方法
<insert id="insertUserTest1" useGeneratedKeys="true" keyProperty="id" parameterType="com.ay.model.AyUser">
        insert into ay_user(name,password) values(#{name},#{password});
    </insert>

对应的AyUserDao,AyUserService接口如下:

int insertUserTest(AyUser ayUser);

实现的AyUserServiceImpl:

public int insertUserTest(AyUser ayUser){
       return ayUserDao.insertUserTest(ayUser);
    }

在控制层进行测试:

 @GetMapping("/insertUserTest")
    public String insertUserTest(Model model) {
        AyUser m =new AyUser();
        m.setId(9);m.setName("ccc");m.setPassword("1234");
        int t=ayUserService.insertUserTest(m);
        System.out.println(t);
        return "hello";
    }

运行80/user/insertUserTest,此时查看数据库信息:
在这里插入图片描述

update元素

用来映射DML语句,主要用来更新数据,同样也会返回一个整数来表示更新的记录数,和select属性差不多。

<update id="updateUser" parameterType="com.ay.model.AyUser">
        update ay_user set name = #{name},password = #{password} where id = #{id}
    </update>

在AyUserDao,AyUserService接口实现:

 int updateUser(AyUser ayUser);

在AyUserServiceImpl中实现:

public int updateUser(AyUser ayUser) {
        return ayUserDao.updateUser(ayUser);
    }

在控制层实现:

@GetMapping("/updateUser")
    public String updateUser(Model model) {
        AyUser m = new AyUser();
        m.setId(1);m.setName("jacinx");m.setPassword("88888");
        int t = ayUserService.updateUser(m);
        return "hello";
    }

运行80/user/updateUser,查看数据库信息:
在这里插入图片描述

delete元素

用来映射删除,和select差不多,这里就稍微写一下xml:

//根据Id删除记录
<delete id ="delete" parameterType = "int">
delete from ay_user where id = #{id}
</delete>

sql元素

sql元素可以用来定义可重用的SQL代码,可以被静态参数化,可以对字段进行封装:

<sql id="userField">
        a.id as "id",
        a.name as "name",
        a.password as "password"
    </sql>
<!--    获取所有用户-->
    <select id="findAll" resultType="com.ay.model.AyUser">
        select
        <include refid="userField"/>
            from ay_user as a

    </select>

当然方便地使用include元素的refid属性进行引用,还可以使用定制使用sql元素,具体如下:

<sql id="userField">
//注意使用$而不是使用#
        ${prefix}.id as "id",
        ${prefix}.name as "name",
        ${prefix}.password as "password"
    </sql>

#与$区别:
#{}将传入的数据当成字符串,会自动加一个双引号,例如:

order by #{id}
//如果id传入为11,那么解析成
order by "11"

${}将数据直接显示在sql中

order by ${id}
order by 11

#方式可以防止sql注入,$无法防止!

动态SQL

在项目开发中,经常根据不同的条件拼接SQL语句,而MyBatis提供了对SQL语句动态的组装能力。采用功能强大的基于OGNL表达式来完成动态SQL。

属性描述
if单条件分支
choose、when、otherwise多条件判断语句,相当于case when
trim、where、set用来处理SQL拼接问题,辅助元素
foreach循环语句

if元素

用来判断语句,比如按照name查询,name可填可不填,如果没填那么就不要使用它来作为查询条件。
if标签常常与test属性联合使用且是必选属性。下面的代码来判断name 或者password是否为空,如果不为空那么就拼凑sql进行查询,如果为空则忽略:

<resultMap id="userMap" type="com.ay.model.AyUser">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="password"/>
    </resultMap>
    <select id="findByNameAndPassword" parameterType="String" resultMap="userMap">
        select <include refid="userField"></include>
            from ay_user a where 1 = 1
            <if test="name != null and name !=''">
                and name = #{name}
            </if>
            <if test="password !=null and password !=''">
                and password = #{password}
            </if>
    </select>

在AyUserDao,AyUserService接口方法:

    List<AyUser> findByNameAndPassword(@Param("name") String name,@Param("password") String password);

在AyUserServiceImpl实现接口的方法:

public List<AyUser> findByNameAndPassword(@Param("name") String name, @Param("password") String password) {
        return ayUserDao.findByNameAndPassword(name,password);
    }

在控制层实现:

  @GetMapping("/findByNameAndPass")
    public String findByNameAndPass(Model model) {
        List<AyUser> a = null;
        a = ayUserService.findByNameAndPassword("ccc","1234");
        for(int i=0;i<a.size();i++) {
            System.out.println(a.get(i).getId()+"  "+a.get(i).getName());
        }
        return "hello";
    }

运行80/user/findByNameAndPass,可以看到控制台打印出相应的信息:

在这里插入图片描述
关于其他的元素例如foreach等就不再赘述了。

Mybatis注解配置

常用注解

除了前面的xml的配置方法,可以使用基于注解的配置方式!
在这里插入图片描述

@Select注解与xml的select相对应,@Results注解与resultMap标签相对应,当使用注解的时候就不用在xml配置了:
在AyUserDao层接口方法:

@Select("select * from ay_user ")
    List<AyUser> findAllUser();

其他AyUserService不变

List<AyUser> findAllUser();

在AyUserServiceImpl中:

public List<AyUser> findAllUser() {
        return ayUserDao.findAllUser();
    }

在控制层实现测试:

@GetMapping("/findAlUser")
    public String findAlUser(Model model) {
        List<AyUser> a = null;
        a = ayUserService.findAllUser();
        for(int i=0;i<a.size();i++) {
            System.out.println(a.get(i).getName());
            System.out.println();
        }
        return "hello";
    }

此时运行就能看到输出了。

其他的例如@Insert,@Update,@Delete类似

@Insert("insert into ay_user(name,password) values(#{name},#{password})")

当映射器需要多个参数,@Param注解可以被应用于映射器方法参数给每个参数取名字。

    List<AyUser> findByNameAndPassword(@Param("name") String name,@Param("password") String password);

MyBatis关联映射

在实际的项目中,需要遵循数据库设计范式的要求,对现实中的业务模块进行拆分,封装到不同的数据表中,表和表之间存在一对多或者多对多的对应关系。进而,对数据库的增删改查的主体从单表就变成了多表。

这里就不再赘述了。

思考:DAO与Service层

不知大家发现没有,在我的上述代码中,DAO与Service层的代码都是一样的,当然这是由于我是表单模式下的。所以这就引发我对DAO与Service层的思考:
这里引用一下zhihu的问题:java为什么要分为service层,dao层,controller层?
在这里插入图片描述
Service类封装业务流程(或者说是界面上的业务流程),DAO类封装对持久层的访问,DTO类封装业务实体对象。为什么要用Service接口和DAO接口?其实就是为了解耦,解耦说的意思是你更改某一层代码,不会影响我其他层代码。
Service + DAO,即DAO中只做CRUD及类似的简单操作(称之为功能点,不包含业务逻辑),Service中通过调用一个或多个DAO中的功能点来组合成为业务逻辑.Service的数量应该由功能模块来决定。在这种模型中业务逻辑是放在Service中的,事务的边界也应该在Service中控制.

以上,希望对你有所帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值