mybatis笔记_2(事务,缓存,orm,表之间的一对一,一对多等关系,动态代理,动态sql,#{}and${},入参规范等等)

1.使用动态代理来实现mybatis。

   动态代理的实现规范:

  • UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
  • UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
  • UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.
  • UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
  • UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
  • UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.bjpowernode.mapper.UsersMapper
  • 在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.bjpowernode.mapper.UsersMapper.

 接口和xml文件在同一目录且名字相同,xml文件就是UserMapper接口的sql语句实现文件,所以

接口中的所有方法名称与id对应,然后namespace命名空间对应接口的位置,最后到mybatis总的配置文件注册一下就行了

<mapper namespace="com.mapper.UserMapper">
    <select id="getAll" resultType="student">
        select id,name,email,age
        from student
    </select>
    <select id="getLickByName" resultType="student" parameterType="string">
        select id,name,email,age
        from student
        where name like '%${name}%'
    </select>

    <insert id="addStudent" parameterType="student">
        insert into student(name, email, age)
        value(#{name},#{email},${age})
    </insert>

    <update id="updateByName" parameterType="student">
        update student set email=#{email},age=#{age}
        where name=#{name}
    </update>
</mapper>

public interface UserMapper {
    List<Student> getAll();

    List<Student> getLickByName(String name);

    int addStudent(Student student);

    int updateByName(Student student);

 }

 注册配置文件:分为单个文件注册和批量注册

<mappers>
<!--    <mapper class="com.mapper.UserMapper"></mapper>-->
    <package name="com.mapper"/>
<!--    包名一次性注册-->
</mappers>

测试的时候任然需要将sqlsession对象取出来,但是可以通过这个获取代理对象usermapper

    SqlSession sqlSession;
    UserMapper userMapper;

    @Before
    public void Before() throws IOException {
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        userMapper=sqlSession.getMapper(UserMapper.class);
    }
    @After
    public void After(){
        sqlSession.close();
    }

    @Test
    public void getAll(){

//        userMapper.getAll();
//
//        List<Student> list = userMapper.getLickByName("李");
//        list.forEach(student -> System.out.println(student));

        Student student=new Student("李四","shagou@qq.com",54);
//        userMapper.addStudent(student);


        userMapper.updateByName(student);
        sqlSession.commit();
    }
}

1.2.#{}占位符

传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.
  #{}里如何写,看parameterType参数的类型
  1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.
    <select id="getById" parameterType="int" resultType="users">  ===>入参类型是简单类型
        select id,username,birthday,sex,address
        from users
        where id=#{zar}  ===>随便写
    </select>  
  2)parameterType的类型是实体类的类型,则#{}里只能是类中成员变量的名称,而且区分大小写. 
    <insert id="insert" parameterType="users" >  ===>入参是实体类
        insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address})  ==>成员变量名称
    </insert>

1.3${}字符串拼接或字符串替换

  1)字符串拼接,一般用于模糊查询中.建议少用,因为有sql注入的风险. 
    也分两种情况,同样的看parameterType的类型
    A. 如果parameterType的类型是简单类型,则${}里随便写,但是分版本,如果是3.5.1及以下的版本,只以写value.
    <select id="getByName" parameterType="string" resultType="users">  ===>入参是简单类型
        select id,username,birthday,sex,address
        from users
        where username like '%${zar}%'   ===>随便写
    </select> 
    B. 如果parameterType的类型是实体类的类型,则${}里只能是类中成员变量的名称.(现在已经少用)
    C. 优化后的模糊查询(以后都要使用这种方式)
    <select id="getByNameGood" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like concat('%',#{name},'%')
    </select> 

多个参数传递注册的情况 

多个参数不用输入注册,但是需要再接口的地方使用注解来定义一下,不然无法接收数据。

如果不使用xml,去使用注解,就可以不需要这个注解,参数直接再最底层的接口实现 

//接口
List<Student> getLick(@Param("key")String key,@Param ("value") String value);

//xml,不用注册输入的类型
    <select id="getLick" resultType="student">
        select name,email,age
        from student
        where ${key} like concat('%',#{value},'%')
    </select>


//直接使用     
 System.out.println(userMapper.getLick("name", "李"));

返回主键值

 在插入语句结束后, 返回自增的主键值到入参的users对象的id属性中.
  <insert id="insert" parameterType="users" >
        <selectKey  keyProperty="id" resultType="int" order="AFTER">
            select last_insert_id()
        </selectKey>
        insert into users (username, birthday, sex, address) values(#{userName},#{birthday},#{sex},#{address})
  </insert>
  <selectKey>标签的参数详解:
    keyProperty: users对象的哪个属性来接返回的主键值
    resultType:返回的主键的类型
    order:在插入语句执行前,还是执行后返回主键的值

 UUID

   这是一个全球唯一随机字符串,由36个字母数字中划线组.
  UUID uuid = UUID.randomUUID();
  System.out.println(uuid.toString().replace("-","").substring(20));

获取一个12位的随机数字字母组合

什么是动态sql 

 可以定义代码片断,可以进行逻辑判断,可以进行循环处理(批量处理),使条件判断更为简单.
  1)<sql>:用来定义代码片断,可以将所有的列名,或复杂的条件定义为代码片断,供使用时调用.
  2)<include>:用来引用<sql>定义的代码片断.
   <!--定义代码片断-->
    <sql id="allColumns">
        id,username,birthday,sex,address
    </sql>
   //引用定义好的代码片断
   <select id="getAll" resultType="users" >
        select <include refid="allColumns"></include>
        from users
    </select>
  3)<if>:进行条件判断
    test条件判断的取值可以是实体类的成员变量,可以是map的key,可以是@Param注解的名称.
  4)<where>:进行多条件拼接,在查询,删除,更新中使用.

  <select id="getCondition" resultType="student" parameterType="student">
        select <include refid="column"></include>
        from student
        <where>
            <if test="name!=null and name!=''">
                and name like concat('%',#{name},'%')
            </if>
            <if test="email!=null and email!=''">
                and email like concat('%',#{email},'%')
            </if>
            <if test="age!=null and age!=''">
                and age like concat('%',#{age},'%')
            </if>

        </where>
    </select>

动态查询,有这些条件就使用,没有就全部查询

这个查询的就是年龄带上1的数据,一般用于多个字段的搜索

Student student=new Student("","",1);
        List<Student> li = userMapper.getCondition(student);
        li.forEach(student1 -> System.out.println(student1));

动态修改

 <update id="updateCondition" parameterType="student" >
        update student
        <set>
            <if test="name!=null and name!=''">
               name=#{name},
            </if>
            <if test="email!=null and email!=''">
               email=#{email},
            </if>
            <if test="age!=null and age!=''">
                age=#{age},
            </if>
        </set>
        where id=#{id}
    </update>

<foreach>:用来进行循环遍历,完成循环条件查询,批量删除,批量增加,批量更新.

查询实现
    

<select id="getByIdS" resultType="student">
        select <include refid="column"></include>
        from student
        where id in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </select>

    <foreach>参数详解:
        collection:用来指定入参的类型,如果是List集合,则为list,如果是Map集合,则为map,如果是数组,则为array.
        item:每次循环遍历出来的值或对象
        separator:多个值或对象或语句之间的分隔符
        open:整个循环外面的前括号 
        close:整个循环外面的后括号

foreach用来批量增加

<insert id="addStudents" parameterType="list">
        insert into student(name, email, age)
        values
        <foreach collection="list" item="s" separator=",">
            (#{s.name},#{s.email},#{s.age})
        </foreach>
    </insert>

foreach用来更改:本质上是执行多条语句,所以需要开启权限

再jdbc文件中修改:最后的一个就是开启多条语句一起执行

jdbc.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
 <update id="updateStdents" parameterType="list">
        <foreach collection="list" item="u" separator=";">
            update student
            <set>
                <if test="u.name!=null">
                    name=#{u.name},
                </if>
                <if test="u.email!=null">
                    email=#{u.email},
                </if>
                <if test="u.age!=null">
                    age=#{u.age}
                </if>
            </set>
            where id=#{u.id}
        </foreach>
    </update>

指定参数位置

  如果入参是多个,可以通过指定参数位置进行传参. 是实体包含不住的条件.实体类只能封装住成员变量的条件.如果某个成员变量要有区间范围内的判断,或者有两个值进行处理,则实体类包不住.
  例如:查询指定年龄范围内的用户信息.直接用这种占位符就行

<select id="getByAge" resultType="student">
    select <include refid="column"></include>
    from student
    where age between #{arg0} and #{arg1}
    </select>

 入参是map(重点掌握) 

 如果入参超过一个以上,使用map封装查询条件,更有语义,查询条件更明确.直接使用map的key,mybatis可以直接拿到value值。

<select id="getByAgeMap" resultType="student">
        select <include refid="column"></include>
        from student
        where age between #{begin} and #{end}
    </select>

@Test
    public void getagemap(){
        Map<String,Integer> map=new HashMap<>();
        map.put("begin",1);
        map.put("end",15);
        List<Student> i = userMapper.getByAgeMap(map);
        i.forEach(student -> System.out.println(student));
        sqlSession.commit();
    }

 .返回值是map

如果返回的数据实体类无法包含,可以使用map返回多张表中的若干数据.返回后这些数据之间没有任何关系.就是Object类型.返回的map的key就是列名或别名.
   <!--
       //返回值是map(一行)
    Map getReturnMap(Integer id);
    -->
    <select id="getReturnMap" parameterType="int" resultType="map">
        select username name,address a
        from users
        where id=#{id}
    </select>
    会返回{name=张三,a=213}
    <!--
      //返回多行的map
    List<Map> getMulMap();
    -->
    <select id="getMulMap" resultType="map">
        select username,address
        from users
    </select>

表之间的关联关系

关联关系是有方向的.
  1)一对多关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在老师方,就是一对多关联.
  2)多对一关联:一个老师可以教多个学生,多个学生只有一个老师来教,站在学生方,就是多对一关联.
  3)一对一关联:一个老师辅导一个学生,一个学生只请教一个老师.学生和老师是一对一.
  4)多对多关联:园区划线的车位和园区的每一辆车.任意一个车位可以停任意一辆车.任意一车辆车可以停在任意一个车位上.
 

一对多实例

首先需要两张表

 然后直接查询的效果

 

 再实体类中定义一个包含另一个类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class students {
    private Integer id;
    private String name;
    private String email;
    private Integer age;

    List<studentCourse> studentCourses;
}


@Data
@AllArgsConstructor
@NoArgsConstructor
public class studentCourse {
    private String name;
    private Integer sno;
    private String sex;
    private String course;
}

在sql中使用的时候没办法直接使用students来承载,必须定义一个resultmap来存放

<resultMap id="students" type="students">
        <id property="id" column="sid"></id>
        <result property="name" column="sname"></result>
        <result property="email" column="email"></result>
        <result property="age" column="age"></result>
        <collection property="studentCourses" ofType="studentCourse">
            <result property="name" column="oname"></result>
            <result property="sno" column="sno"></result>
            <result property="sex" column="sex"></result>
            <result property="course" column="course"></result>
        </collection>
    </resultMap>
    <select id="getByName" parameterType="string" resultMap="students">
        select s.id sid,s.name sname,email,age,o.name oname,sno,sex,course
        from student_one o join student s on o.name=s.name
        where o.name=#{name}
    </select>

这个标签只是为了定义一个承载类型,collection集合用于存放循环的相同数据

最后直接执行就行

.多对一关联关系.
  订单和客户就是多对一关联.
  站在订单的方向查询订单的同时将客户信息查出.
  订单是多方,会持有一方的对象.客户是一方.
  <mapper namespace="com.bjpowernode.mapper.OrdersMapper">
    <!--
      //根据主键查询订单,并同时查询下此订单的客户信息
    Orders getById(Integer id);
    -->

    <!--
      手工绑定数据
      实体类
        private Integer id;
        private String orderNumber;
        private Double orderPrice;

        //关联下此订单的客户信息,多方持有一方的对象
        private Customer customer;
    -->
    <resultMap id="ordersmap" type="orders">
        <!--主键绑定-->
        <id property="id" column="oid"></id>
        <!--非主键绑定-->
        <result property="orderNumber" column="orderNumber"></result>
        <result property="orderPrice" column="orderPrice"></result>
        <!--多出来的一咕噜绑定
            private Integer id;
            private String name;
            private Integer age;

            //该客户名下的所有订单的集合,一方持有多方的集合
            private List<Orders> ordersList; //不用管
        -->
        <association property="customer" javaType="customer">
            <id property="id" column="cid"></id>
            <result property="name" column="name"></result>
            <result property="age" column="age"></result>

        </association>
    </resultMap>
    <select id="getById" parameterType="int" resultMap="ordersmap">
        select o.id oid,orderNumber,orderPrice,customer_id,c.id cid,name,age
        from orders o inner join customer c on o.customer_id = c.id
        where o.id=#{id}
    </select>
  </mapper>

值得注意的是,实体类中包含其他实体类使用association标签来包含

事务

多个操作同时完成,或同时失败称为事务处理.
  事务有四个特性:一致性,持久性,原子性,隔离性.

  下订单的业务:
  1)订单表中完成增加一条记录的操作
  2)订单明细表中完成N条记录的增加
  3)商品数据更新(减少)
  4)购物车中已支付商品删除
  5)用户积分更新(增加)

  在MyBatis框架中设置事务
  <transactionManager type="JDBC"></transactionManager>  ===>程序员自己控制处理的提交和回滚

  可设置为自动提交
  sqlSession = factory.openSession();  ===>默认是手工提交事务,设置为false也是手工提交事务,如果设置为true,则为自动提交.
  sqlSession = factory.openSession(true);  ===>设置为自动提交,在增删改后不需要commit();

.缓存

  MyBatis框架提供两级缓存,一级缓存和二级缓存.默认开启一级缓存.

  缓存就是为了提交查询效率.

  使用缓存后,查询的流程:
  查询时先到缓存里查,如果没有则查询数据库,放缓存一份,再返回客户端.下次再查询的时候直接从缓存返回,不再访问数据库.如果数据库中发生commit()操作,则清空缓存.

  一级缓存使用的是SqlSession的作用域,同一个sqlSession共享一级缓存的数据.
  二级缓存使用的是mapper的作用域,不同的sqlSession只要访问的同一个mapper.xml文件,则共享二级缓存作用域.

什么是ORM

ORM(Object Relational Mapping):对象关系映射
  MyBatis框架是ORM非常优秀的框架.
  java语言中以对象的方式操作数据,存到数据库中是以表的方式进行存储,对象中的成员变量与表中的列之间的数据互换称为映射.整个这套操作就是ORM.

  持久化的操作:将对象保存到关系型数据库中 ,将关系型数据库中的数据读取出来以对象的形式封装

  MyBatis是持久化层优秀的框架.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值