MyBatis中的动态代理

1.动态代理存在的意义

在三层架构中,业务逻辑层要通过接口访问数据访问层的功能.动态代理可以实现.

2.动态代理的规范

在这里插入图片描述

1.UsersMapper.xml文件与UsersMapper.java的接口必须同一个目录下.
2.UsersMapper.xml文件与UsersMapper.java的接口的文件名必须一致,后缀不管.
在这里插入图片描述
3.UserMapper.xml文件中标签的id值与与UserMapper.java的接口中方法的名称完全一致.

UserMapper接口

package com.xin.mapper;

import com.xin.pojo.Users;

import java.util.List;

/**
 * 数据访问层的接口,规定数据库中可进行的各种操作
 */
public interface UsersMapper {
    //查询全部用户信息
    List<Users> getAll();
    //根据用户主键查用户
    Users getById(Integer id);
    //根据用户名模糊查询用户
    List<Users> getByName(String name);
    //用户更新
    int update(Users users);
    //增加用户
    int insert(Users users);
    //根据主键删除用户
    int delete(Integer id);
}

UserMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xin.mapper.UsersMapper">
    <!--
        //查询全部用户信息
        List<Users> getAll();
    -->
    <select id="getAll" resultType="users">
        select id,username,birthday,sex,address
        from users
    </select>
    <!--
        //根据用户主键查用户
        Users getById(Integer id);
    -->
    <select id="getById" parameterType="int" resultType="users">
        select id,username,birthday,sex,address
        from users
        where id=#{id}
    </select>
    <!--
         //用户更新
         int update(Users users);
         private Integer id;
         private String userName;
         private Date birthday;
         private String sex;
         private String address;
    -->
    <update id="update" parameterType="users">
        update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address}
        where id=#{id}
    </update>
    <!--
        //根据用户名模糊查询用户
        List<Users> getByName(String name);
    -->
    <select id="getByName" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like '%${name}%'
    </select>
    <!--
        //增加用户
        int insert(Users users);
    -->
    <insert id="insert" parameterType="users">
        insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})
    </insert>
    <!--
        //根据主键删除用户
        int delete(Integer id);
    -->
    <delete id="delete" parameterType="int">
        delete from users
        where id=#{id}
    </delete>
</mapper>

4.UserMapper.xml文件中标签的parameterType属性值与与UserMapper.java的接口中方法的参数类型完全一致.
5.UserMapper.xml文件中标签的resultType值与与UserMapper.java的接口中方法的返回值类型完全一致.
6.UserMapper.xml文件中namespace属性必须是接口的完全限定名称com.xin.mapper.UsersMapper
7.在SqlMapConfig.xml文件中注册mapper文件时,使用class=接口的完全限定名称com.xin.mapper.UsersMapper.

3.动态代理访问的步骤

1)建表Users
2)新建maven工程,刷新可视化
3)修改目录
在这里插入图片描述

4)修改pom.xml文件,添加依赖

   <!--添加mysql依赖-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.17</version>
    </dependency>
     <!--添加MyBatis框架依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
    </dependency>
  </dependencies>
  <!--添加指定文件的指定(不指定,所有非java文件不会copy到target里)-->
  <build>
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.xml</include>
          <include>**/*.properties</include>
        </includes>
      </resource>
    </resources>
  </build>

5)添加jdbc.propertis文件到resources目录下
在这里插入图片描述
jdbc.propertis文件

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root

6)添加SqlMapConfig.xml文件
SqlMapConfig.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>
    <!--读取jdbc.properties属性文件-->
    <properties resource="jdbc.properties"></properties>
    <!--设置日志输出-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--注册实体类别名-->
    <typeAliases>
         <package name="com.xin.pojo"/>
    </typeAliases>
    <!--配置环境变量-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
               <!--private String driver;
                    private String url;
                    private String username;
                    private String password;
                -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--注册mapper.xml文件-->
    <mappers>
<!--     单个实体类注册别名
        <mapper class="com.xin.mapper.UsersMapper"></mapper>&lt;!&ndash;填写的是接口的引用路径&ndash;&gt;
-->
        <!--批量注册别名-->
        <package name="com.xin.mapper"></package>
    </mappers>

</configuration>

7)添加实体类

package com.xin.pojo;

import java.util.Date;

public class Users {
    private Integer id;
    private String userName;
    private Date birthday;
    private String sex;
    private String address;

    public Users() {
    }

    public Users(Integer id, String userName, Date birthday, String sex, String address) {
        this.id = id;
        this.userName = userName;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Users(String userName, Date birthday, String sex, String address) {
        this.userName = userName;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Users{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

8)添加mapper文件夹,新建UsersMapper接口
9)在mapper文件夹下,新建UsersMapper.xml文件,完成增删改查功能
在这里插入图片描述
UsersMapper接口

package com.xin.mapper;

import com.xin.pojo.Users;

import java.util.List;

/**
 * 数据访问层的接口,规定数据库中可进行的各种操作
 */
public interface UsersMapper {
    //查询全部用户信息
    List<Users> getAll();
    //根据用户主键查用户
    Users getById(Integer id);
    //根据用户名模糊查询用户
    List<Users> getByName(String name);
    //用户更新
    int update(Users users);
    //增加用户
    int insert(Users users);
    //根据主键删除用户
    int delete(Integer id);
}

UsersMapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xin.mapper.UsersMapper">
    <!--
        //查询全部用户信息
        List<Users> getAll();
    -->
    <select id="getAll" resultType="users">
        select id,username,birthday,sex,address
        from users
    </select>
    <!--
        //根据用户主键查用户
        Users getById(Integer id);
    -->
    <select id="getById" parameterType="int" resultType="users">
        select id,username,birthday,sex,address
        from users
        where id=#{id}
    </select>
    <!--
         //用户更新
         int update(Users users);
         private Integer id;
         private String userName;
         private Date birthday;
         private String sex;
         private String address;
    -->
    <update id="update" parameterType="users">
        update users set username=#{userName},birthday=#{birthday},sex=#{sex},address=#{address}
        where id=#{id}
    </update>
    <!--
        //根据用户名模糊查询用户
        List<Users> getByName(String name);
    -->
    <select id="getByName" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like '%${name}%'
    </select>
    <!--
        //增加用户
        int insert(Users users);
    -->
    <insert id="insert" parameterType="users">
        insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})
    </insert>
    <!--
        //根据主键删除用户
        int delete(Integer id);
    -->
    <delete id="delete" parameterType="int">
        delete from users
        where id=#{id}
    </delete>
</mapper>

10)添加测试类,测试功能

package com.xin.test;

import com.xin.mapper.UsersMapper;
import com.xin.pojo.Users;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

public class MyTest {
    SqlSession sqlSession;
    //动态代理对象
    UsersMapper usersMapper;
    //日期的格式化
    SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd");
    @Before
    public void openSqlSession() throws IOException {
        //使用文件流读取核心配置文件SqlMapConfig.xml
        InputStream in= Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory工厂对象
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(in);
        //取出SqlSession对象
        sqlSession=sqlSessionFactory.openSession();
        //取出动态代理对象,完成接口中方法的调用,实则是调用xml文件中相应标签的功能
        usersMapper=sqlSession.getMapper(UsersMapper.class);
    }
    @After
    public void closeSqlSession() {
        sqlSession.close();
    }
    @Test
    public void testGetAll() {
        /*
        //取出动态代理对象,完成接口中方法的调用,实则是调用xml文件中相应标签的功能
        UsersMapper usersMapper=sqlSession.getMapper(UsersMapper.class);
        System.out.println(usersMapper.getClass());//class com.sun.proxy.$Proxy7
        */
        //调用接口中的方法,mybatis框架已经为我们把功能代理出来了
        List<Users> list=usersMapper.getAll();
        list.forEach(users-> System.out.println(users));
    }
    @Test
    public void testById() {
/*
        usersMapper=sqlSession.getMapper(UsersMapper.class);
*/
        Users users= usersMapper.getById(2);
        System.out.println(users);
    }
    @Test
    public void testUpdate() throws ParseException {
        Users users=new Users(7,"Lihua",sf.parse("2000-01-01"),"2","北京");
        int num=usersMapper.update(users);
        System.out.println(num);
        //切记切记切记:手工提交事务
        sqlSession.commit();
    }
    @Test
    public void testByName() {
/*
        List<Users> list=usersMapper.getByName("'or 1=1 or 1='");//sql注入
*/
        List<Users> list=usersMapper.getByName("张");
        list.forEach(users-> System.out.println(users));
    }
    @Test
    public void testInsert() throws ParseException {
        Users users=new Users("tom",sf.parse("2000-12-24"),"21","河南周口");
        int num=usersMapper.insert(users);
        System.out.println(num);
        sqlSession.commit();
    }
    @Test
    public void testDelete() {
        int num=usersMapper.delete(29);
        System.out.println(num);
        sqlSession.commit();
    }
}

4.优化mapper.xml文件注册

<!--注册mapper.xml文件-->
<mappers>
    <!--绝对路径注册-->
    <mapper url="/"></mapper>
    <!--非动态代理方式下的注册-->
    <mapper resource="StudentMapper.xml"></mapper>
    <!--动态代理方式下的单个mapper.xml文件注册-->
    <mapper class="com.bjpowernode.mapper.UsersMapper"></mapper>
    <!--批量注册-->
    <package name="com.bjpowernode.mapper"></package>
</mappers> 

5.#{}占位符

传参大部分使用#{}传参,它的底层使用的是PreparedStatement对象,是安全的数据库访问 ,防止sql注入.
#{}里如何写,看parameterType参数的类型
1)如果parameterType的类型是简单类型(8种基本(封装)+String),则#{}里随便写.

===>入参类型是简单类型
    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>

6. ${}字符串拼接或字符串替换

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:模糊查询

<!--
        //根据用户名模糊查询用户
        List<Users> getByName(String name);
    -->
    <select id="getByName" parameterType="string" resultType="users">
        select id,username,birthday,sex,address
        from users
        where username like '%${name}%'
    </select>

测试:

@Test
    public void testByName() {
        List<Users> list=usersMapper.getByName("'or 1=1 or 1='");//sql注入
//        List<Users> list=usersMapper.getByName("张");
        list.forEach(users-> System.out.println(users));
    }

在这里插入图片描述
由于输入的是" ‘or 1=1 or 1=’ ",存在SQL注入,所有的信息都被查了出来
D. 优化后的模糊查询(以后都要使用这种方式)

<select id="getByNameGood" parameterType="string" resultType="users">
       select id,username,birthday,sex,address
       from users
       where username like concat('%',#{name},'%')
</select>

测试:

@Test
    public void testByNameGood() {
        List<Users> list=usersMapper.getByNameGood("'or 1=1 or 1='");
//        List<Users> list=usersMapper.getByName("张");
        list.forEach(users -> System.out.println(users));
    }

在这里插入图片描述
where usernamelike concat(‘%’,#{name},‘%’)使用了字符串拼接,防止了SQL注入,查不到任何信息
2)字符串替换用${}
需求:模糊地址或用户名查询
select * from users where username like ‘%小%’;
select * from users where address like ‘%市%’

  <!--
    //模糊用户名和地址查询
    //如果参数超过一个,则parameterType不写
    List<Users> getByNameOrAddress(
            @Param("columnName")  ===>为了在sql语句中使用的名称
            String columnName,
            @Param("columnValue")   ===>为了在sql语句中使用的名称
            String columnValue);
    -->
    <select id="getByNameOrAddress" resultType="users">
        select id,username,birthday,sex,address
        from users
        where ${columnName} like concat('%',#{columnValue},'%')  ==>此处使用的是@Param注解里的名称
    </select>

测试;

@Test
    public void testGetByNameOrAddress() {
        List<Users> list=usersMapper.getByNameOrAddress("username","小");
        list.forEach(users-> System.out.println(users));
    }

在这里插入图片描述

@Test
    public void testGetByNameOrAddress() {
//        List<Users> list=usersMapper.getByNameOrAddress("username","小");
        List<Users> list=usersMapper.getByNameOrAddress("address","市");
        list.forEach(users-> System.out.println(users));
    }

在这里插入图片描述

7.返回主键值

 <insert id="insert" parameterType="users">
        insert into users(username,birthday,sex,address) values(#{userName},#{birthday},#{sex},#{address})
    </insert>

测试:

 @Test
    public void testInsert() throws ParseException {
        Users users=new Users("uu",sf.parse("2000-12-24"),"21","河南周口");
        int num=usersMapper.insert(users);
        System.out.println(num);
        System.out.println(users);
        sqlSession.commit();
    }

在这里插入图片描述
可以看到,主键id=null,是因为在创建Users对象时,并没有给id传参,所以为null

在插入语句结束后, 返回自增的主键值到入参的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>

标签的参数详解:
keyProperty: users对象的哪个属性来接返回的主键值
resultType:返回的主键的类型
order=“BEFORE”:在执行inser插入语句执行前,返回主键的值
order=“AFTER”:执行insert插入语句后返回主键的值

测试:

@Test
    public void testInsert() throws ParseException {
        Users users=new Users("uu",sf.parse("2000-12-24"),"21","河南周口");
        int num=usersMapper.insert(users);
        System.out.println(num);
        System.out.println(users);
        sqlSession.commit();
    }

在这里插入图片描述

8.UUID

这是一个全球唯一随机字符串,由36个字母数字中划线组成.

UUID uuid = UUID.randomUUID();
System.out.println(uuid.toString().replace("-","").substring(20));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老衲只用阿道夫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值