02-mybatis深入理解参数

探究
在这里插入图片描述
关于update、delete、insert一定要看这篇文章Mybatis系列第6篇:恕我直言,mybatis增删改你未必玩得转!

parameterType

parameterType:接口中方法参数的类型,类型的完全限定名或别名。这个属性是可选的,因为Mybatis可以推断出具体传入语句的参数,默认值为为设置(unset)。接口中方法的参数从java代码传入到mapper文件的sql语句。
1、创建一个maven项目。
2、引入mybatis、junit、mysql的依赖
3、在src\main\java下,创建com.yongbin.dao、·com.yongbin.domain、创建·com.yongbin.utils三个包。

首先在com.yongbin.dao创建一个通过学生的id查询学生信息的方法。

/**
 * 操作mybatis中的student表
 * @author 刘瘦瘦
 * @create 2021-07-13-15:38
 */
public interface StudentDao {
    /**
     *查询学生信息
     */
    public Student selectStudentById(int id);
}

com.yongbin.dao目录下创建sql映射文件(mapper文件):
mapper文件的要求

  1. 作用:mapper文件是写sql语句的。一般一个表一个sql映射文件。这个文件是xml文件。
  2. 该文件写在接口所在的目录中(和StudentDao在同一个目录)
  3. 文件的名称和接口保持一致。

StudentDao.xml中的配置如下:

<!--
    namespace:要写你的接口的权限定路径
-->
<!--
    namespace:要写你的接口的权限定路径
-->
<mapper namespace="com.yongbin.dao.StudentDao">

    <!--
        1.id:要写你的接口中的方法名
        2.parameterType:接口中方法参数的类型,可以使用mybatis提供的别名
          也可以是数据类型的全限定路径。
          parameterType不是强制的,mybatis通过反射机制能够发现接口参数的类型。,所以可以不写,我们一般也不写
        3.reuresultType要和调用方法的返回值是一样的。
          它有两种形式:1. 类型的全限定名称(建议)   2. 类型的别名, 例如 java.lang.Integer别名是int
        4.sql语句中的#{sid},是占位符的意思,就是把调用的dao中的方法的参数传递给下面的占位符,当dao中的方法
            是一个参数时,这里的名字可以随意起。如#{dog},#{dogleg},#{mary}
        5.
    -->
    <select id="selectStudentById" parameterType="Integer" resultType="com.yongbin.domain.Student">
        select * from student where id=#{sid}
    </select>

</mapper>

运行当然可以运行,这里偷个懒。

MyBatis 传递参数

从 java 代码中把参数传递到 mapper.xml 文件。
在这里插入图片描述

mybatis的主配置文件,mybatis.xml的内容如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--环境配置:数据库的连接信息
        default:必须和某个environment的id值一样。
        告诉mybatis使用哪个数据库的连接信息。也就是访问哪个数据库
    -->
    <environments default="mydev">
        <environment id="mydev">
            <!--
                transactionManager:mybatis的事务类型
                    type:JDBC(表示使用jdbc中的Connection对象的commit,rollback做事务处理)
            -->
            <transactionManager type="JDBC"/>
            <!--
                dataSource:表示数据源,连接数据库的
                    type:表示数据源的类型,POOLED表示使用连接池
            -->
            <dataSource type="POOLED">
                <!--
                    driver、url、username、password是固定的,不能自定义。
                -->
                <!--数据库的驱动类名-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--连接数据库的url字符串-->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <!--访问数据库的用户名-->
                <property name="username" value="root"/>
                <!--密码-->
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <!--sql mapper(sql映射文件)的位置-->
    <mappers>
        <!--
            一个mapper标签指定一个文件的位置。
            从类路径开始的路径信息。 target/clasess(类路径)-->
        <mapper resource="com/yongbin/dao/StudentDao.xml"/>
        <!--可以配置多个-->
        <!--<mapper resource="com/yongbin/dao/StudentDao.xml"/>-->
    </mappers>
</configuration>

StudentDao的内容如下:

/**
 * 操作mybatis中的student表
 * @author 刘瘦瘦
 * @create 2021-07-13-15:38
 */
public interface StudentDao {

    /**
     *查询学生信息,测试mapper文件中的parameterType
     * parameterType:接口中方法参数的类型,可以使用mybatis提供的别名也可以是数据类型的全限定路径。
      parameterType不是强制的,mybatis通过反射机制能够发现接口参数的类型。,所以可以不写,我们一般也不写
     */
    public Student selectStudentById(int id);

    /**
     * 以下测试mybatis传递参数:从java代码中把参数传递到mapper.xml文件
     */
    public Student selectStudentById2(int id);

    /**
     * 测试多个参数使用:@Param
     * 当dao接口方法中有多个参数,需要通过名称使用参数。在方法形参前加入@Param("自定义参数名")
     * mapper文件中使用#{"自定义参数名"}
     */
    public List<Student> selectMultiParam(@Param("dogleg") String name,@Param("catleg") int id);

    /**
     * 多个参数--使用对象:
     * 使用 java 对象传递参数, java 的属性值就是 sql 需要的参数值。 每一个属性就是一个参数。
     语法格式: #{ property,javaType=java 中数据类型名,jdbcType=数据类型名称 }
     javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。常用格式 #{ property }
     */
    public int selectStudentCountByObject(Student student);

    /**
     *多个参数--按位置
     * 参数位置从0开始,引用参数语法#{arg位置}
     * 注意:mybatis-3.3 版本和之前的版本使用#{0},#{1}方式, 从 mybatis3.4 开始使用#{arg0}方式。
     */
    public Student selectStudentByPos(int id,String name);

    /**
     * 多个参数--使用Map
     * Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,
     Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值。
     */
    public List<Student> selectMultiParamByMap(Map<String,Object> map);
}

测试方法如下:

/**
 * @author 刘瘦瘦
 * @create 2021-07-13-16:06
 */
public class testStudentDao {

    //测试ParametType
    @Test
    public void testParamType() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        Student student = stuImpl.selectStudentById(1003);
        System.out.println(student);
    }

    /*
       mybatis传递参数:1 简单类型 dao接口中的参数只有一个简单类型(java基本类型和String类型)
       #{任意字符,和方法的参数名无关}
     */
    @Test
    public void testSelectStudentById2() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        Student student = stuImpl.selectStudentById2(1003);
        System.out.println(student);
    }

    /*
       mybatis传递参数:2 多个参数,自定义 :@Param("自定义参数名")
     */
    @Test
    public void testSelectMultiParam() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        List<Student> studentList = stuImpl.selectMultiParam("galigaygay", 1003);
        for(Student stu:studentList){
            System.out.println(stu);
        }
    }

    /**
     * 多个参数--使用对象:
     */
    @Test
    public void testSelectStudentCountByObject() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        int count=stuImpl.selectStudentCountByObject(new Student(1003,"galigaygay","galigaygay.@qq.com",23));
        System.out.println(count);
    }

    /**
     * 多个参数--使用位置:
     */
    @Test
    public void testSelectStudentByPos() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        Student student = stuImpl.selectStudentByPos(1002,"lisi");
        System.out.println(student);
    }

    /**
     * 多个参数--使用map:
     */
    @Test
    public void testSelectMultiParamByMap() throws IOException {
        //获取SQLSession对象
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        //获取StudentDaoImpl对象
        StudentDao stuImpl = sqlSession.getMapper(StudentDao.class);
        //执行方法
        Map<String,Object> map=new HashMap<>();
        map.put("myname","galigaygay" );
        map.put("myage",22 );
        List<Student> students = stuImpl.selectMultiParamByMap(map);
        students.forEach(System.out::println);
    }
}

#和$的区别

#占位符:告诉mybatis使用实际的参数值代替。并使用PrepareStatement对象执行sql语句,#{…}代替sql语句的·?·。这样做更安全,更迅速,通常也是首选做法。
如下面的StudentDao.xml(mapper文件)的声明:

    <select id="selectMultiParam4" resultType="com.yongbin.domain.Student">
        select id,name,email,age from student where id=#{myId} or name=#{myName};
    </select>

当运行时,转换为的sql语句为:
在这里插入图片描述
相当于执行的是:

String sql="select id,name,email,age from student where id=? or name=?
PreparedStatement ps=conn.prepareStatement(sql);
ps.setInt(1,1005);
ps.setString(2,"lisi");

解释:where id=? or name=?就是 where id=#{myid} or name=#{myname}
ps.setInt(1,1005),1005会替换掉#{myid}

$字符串替换告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和 ${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。
如下面的在StudentDao中定义的方法:

 List<Student> selectUse$(@Param("myname") String name);

StudentDao.xml中的配置如下:

    <!--
    $作为占位符,会引起sql注入
    -->
    <select id="selectUse$" resultType="com.yongbin.domain.Student">
        select id,name,email,age from student where  name=${myname}
    </select>

相当于:
在这里插入图片描述
上述结果发生了sql注入的问题。

封装Mybatis输出结果

在这里插入图片描述

returnType

returnType:执行sql得到的ResultSet转换的类型,使用类型的完全限定名(建议使用)或别名。注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。resultType和resultMap,不能同时使用。

简单类型
在StudentDao中定义如下的方法:

    //查询表中的总记录数
    int countStudent();

mapper文件(StudentDao.xml)中:

    <!--
      resultType要和调用方法的返回值是一样的。
         它有两种形式:1. 类型的全限定名称(建议)   2. 类型的别名, 例如 java.lang.Integer别名是int--这是mybatis定义的

    <select id="countStudent" resultType="int">
     这里的int使用的是别名,更多别名参考官方文档
    -->
    <select id="countStudent" resultType="java.lang.Integer">
        select count(*) from student
    </select>

测试方法如下:

//resultType结果类型的它值 1. 类型的全限定名称   2. 类型的别名, 例如 java.lang.Integer别名是int
    @Test
    public void testCountStudent() throws IOException {
        /**
         * 使用mabtis的动态代理机制,使用SqlSession.getMapper(dao接口)
         *   getMapper能获取dao接口对应的实现类对象
         */
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        System.out.println(dao.countStudent());

    }

在上面的apper.xml中,我们使用了官方的别名int代替了全限定路径java.lang.Integer,尽然可以使用官方定义的别名,那么我们可不可以自己定义别名呢?当然可以,在下面的语句上,使用别名。

<select id="selectMultiParam2" resultType="com.yongbin.domain.ViewStudent">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
    </select>

如何自定义别名来用更少的字母代替"com.yongbin.domain.ViewStudent",可以共有两种方式,需要在mybatsi.xml(主配置文件中进行配置)
alias的汉语意思就是别名的意思。

<!--定义别名:方式一-->
    <typeAliases>
        <!-- 第一种方式
          可以指定一个类型,一个自定义的别名
            type:自定义类型的全限定名称
            alias:别名(短小,容易记忆)

           一个<typeAlias>定义一个类型的别名
        -->
        <!--<typeAlias type="com.yongbin.domain.Student" alias="stu"></typeAlias>-->
        <!--<typeAlias type="com.yongbin.domain.ViewStudent" alias="vstu"></typeAlias>-->

        <!--第二种方式
            <package> name是包名,这个包中的所有类,类名就是别名(类名不区分大小写)
        -->
        <package name="com.yongbin.domain"></package>

    </typeAliases>

但是使用第二种方式会发生冲突问题

  比如现在有两个包:
         com.yongbin.domain
         com.yongbin.vo 两个包下面都有Student类,而mybatis中的

         <typeAliases>
         <package type="com.yongbin.domain" ></package>
        <package type="com.yongbin.vo" ></package>
        </typeAliases>

        那么:这样就会冲突
        <select id="selectMultiParam2" resultType="Student">
        select id,name,email,age from student where name=#{myname} or age=#{myage}
       </select>

       建议还是使用全限定路径。

B对象类型
在StudentDao中定义如下的方法:

 public Student selectStudentById(Integer id);

StudentDao.xml文件的配置如下:

   mybatis在组建对象时,实体类可以没有set、get方法,但是必须和数据库中的字段名字一样(大小写均可)
     比如:数据库中的字段是age   你的实体类中的可以是Age、AGE ,但是不能是其他:如safsdaf
    <select id="selectStudentById" resultType="com.yongbin.domain.Student">
        select id,name,email,age from student where id=#{id}
    </select>

注意:Dao接口方法返回是集合类型,需要指定集合中的类型,不是集合本身
在这里插入图片描述
Map类型
在StudentDao中声明的抽象方法为:下面演示的是,返回一行的map形式,和返回多行的map形式。

  //返回map的形式
    Map<Object,Object> returnMapFormById(@Param("myid")int id);

    //多行数据以map的形式返回
    List<Map<Object,Object>> returnMapFormMultiLines(@Param("myid")int id);

mapper(StudentDao.xml)中的配置如下:

<!--返回map
        1、列名是map的key,列值是map的value
        2.下面的只能返回一行数据
        3.多行数据以map的形式返回,见下面例子
    -->
    <select id="returnMapFormById" resultType="java.util.Map">
        select * from student where id=#{myid}
    </select>
    <!-- 3.多行数据以map的形式返回,见下面例子-->
    <select id="returnMapFormMultiLines" resultType="java.util.Map">
        select * from student where id >#{myid}
    </select>

//测试map--单行
    @Test
    public void testReturnMapForm() throws IOException {
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        Map<Object, Object> maps = studentDao.returnMapFormById(1003);
        System.out.println(maps);
    }
    //测试map--多行
    @Test
    public void testReturnMapFormMultiLines() throws IOException {
        SqlSession sqlSession = MyBaitsUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        List<Map<Object, Object>> maps = studentDao.returnMapFormMultiLines(1001);
        System.out.println(maps);
    }

测试单行的结果:
在这里插入图片描述
测试多行的结果:
在这里插入图片描述
mybatis在组建对象时,实体类可以没有set、get方法,但是必须和数据库中的字段名字一样(大小写均可)
比如:数据库中的字段是age 你的实体类中的可以是Age、AGE ,但是不能是其他:如safsdaf,解决这个问题可以使用returnMap和别名的方式。

returnMap

resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。常用在列名和 java 对象属性名不一样的情况
基本使用方式举例:

  1. 先定义resultMap,指定列名和属性的对应关系。
  2. 在、等中把resultType替换为resultMap。
    接口中定义的方法如下:
//使用resultMap定义映射关系
    List<Student> selectAllStudents();

StudentDao.xml中的定义如下:

<!--
        定义resultMap
        id:自定义名称,表示你定义的这个resultMap
        type:java类型的全限定名称
    -->
    <resultMap id="studentMap" type="com.yongbin.domain.Student">
        <!--列名和java属性的关系-->
        <!--主键列,使用id标签
            column:列名
            property:java类型的属性名
        -->
        <id column="id" property="id"></id>
        <!--非主键列,使用result-->
        <result column="name" property="name"></result>
        <result column="email" property="email"></result>
        <result column="age" property="age"></result>

        <!--使用resultMap的话,必须要提供set方法-->
        <!--这个resultMap可以被复用-->
    </resultMap>


    <select id="selectAllStudents" resultMap="studentMap">
        select * from student
    </select>

解决数据库的字段名和实体类中的属性不一致的问题:
我们上述演示的Student类中的属性都和数据库表中的字段名一致:
在这里插入图片描述
下面我们重新定义一个MyStudent实体类,它和数据库表中的字段名不一样。
在这里插入图片描述
现在使用resultMap来解决。StudentDao中定义如下的方法:
在这里插入图片描述
StudentDao.xml中的声明如下:

<!--列名和属性名不一致怎么办?
        方式一:使用上面的resultMap
    -->
    <resultMap id="mystudent" type="com.yongbin.domain.MyStudent">
        <id column="id" property="stuid"></id>
        <result column="name" property="stuname"></result>
        <result column="email" property="stuemail"></result>
        <result column="age" property="stuage"></result>
    </resultMap>

    <select id="selectAllMyStudents" resultMap="mystudent">
        select * from student;
    </select>

测试方法如下:

 /*
    resultMap:结果映射,指定列名和java对象的属性对应关系。
       1.你自定义列值赋值给哪个属性
       2.当你的列名和属性名不一样时,一定是要resultMap
     */
 @Test
    public void testSelectAllStudents() throws IOException {
        SqlSession sqlSession=MyBaitsUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        List<MyStudent> MyStudent = studentDao.selectAllMyStudents();
        for(MyStudent student :MyStudent){
            System.out.println(student);
        }
    }

运行结果:
在这里插入图片描述
方法二,解决列名和属性名不一致问题,使用别名
StudentDao中的声明如下:

//表中的字段名和类中的属性名不一致,该怎么办?方式二:使用别名
    //因为mybatis创建对象为其赋值时,是根据字段名和类中的属性名的一致来进行的
    List<MyStudent> selectAllMyStudents2();

StudentDao.xml中的配置:

<!--列名和属性名不一致怎么办?
     方式二:使用别名
    -->
    <select id="selectAllMyStudents2" resultType="com.yongbin.domain.MyStudent">
        select id as stuid,name as stuname,email as stueamil,age as stuage from student;
    </select>

测试方法:

 /*
    列名和属性名不一致怎么办?
    方式二:sql语句使用别名
    */
    @Test
    public void testSelectAllMyStudents2() throws IOException {
        SqlSession sqlSession=MyBaitsUtil.getSqlSession();
        StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
        List<MyStudent> students = studentDao.selectAllMyStudents2();
        for(MyStudent student :students){
            System.out.println(student);
        }
    }

运行结果:
在这里插入图片描述

模糊查询

模糊查询的实现有两种方式,一是java代码中给查询数据加上%;二是在mapper文件sql语句的条件位置上加%

要求:查询姓名有“力”的
例子1、java代码中提供要查询的%力
接口中的方法:
在这里插入图片描述
例子2、mapper 文件中使用 like name "%" #{xxx} "%"
在这里插入图片描述

mybatis对parameterType和resultType定义的别名

系统已定义的别名直接在xml中文件中引用别名就可,不需要再写对应的全称类名,减少代码的书写量
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值