MyBatis(二)基于代理Dao实现CRUD操作

1.基于代理Dao实现CRUD操作

  • 从上一文章中可以知道mybatis环境搭建的步骤:
    第一步:创建 maven 工程
    第二步:导入坐标
    第三步:编写必要代码(实体类和持久层接口)
    第四步:编写 SqlMapConfig.xml
    第五步:编写映射配置文件
    第六步:编写测试类

1.1 编写实体类和持久层接口

  • 首先,创建一个maven工程,配置pom.xml,然后编写一个用户的实体类(上章有相关配置)
  • 下面创建持久层接口,定义一些方法:查询所有方法、根据ID查询、插入、更新、根据Id删除用户、根据名称模糊查询和聚合函数查询
  • IUserDao.java
public interface IUserDao {
    /**
     * 查询所有
     * @return
     */
    List<User> findAll();

    /**
     * 根据Id查询用户
     * @param userId
     */
    User findById(Integer userId);

    /**
     * 保存用户
     * @param user
     */
    void saveUser(User user);
    /**
     * 更新用户
     * @param user
     */
    void  updateUser(User user);

    /**
     * 根据Id删除用户
     * @param userId
     */
    void deleteUser(Integer userId);

    /**
     * 根据名称模糊查询
     * @param username
     * @return
     */
    List<User> findByName(String username);

    /**
     * 查询总记录数
     * @return
     */
    Integer findtotal();
}

1.2 编写主配置文件

  • 数据库配置文件jdbcConfig.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///eesy
jdbc.username=root
jdbc.password=root
  • mybatis的主配置文件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">
<!--mybatis的主配置文件-->
<configuration>
    <!-- 配置properties-->
    <properties resource="jdbcConfig.properties"></properties>
    <!-- 配置环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/wink/dao/IUserDaoMapper.xml"></mapper>
    </mappers>
</configuration>

1.3 编写映射配置文件

  • 在用户的映射配置文件中配置用户的持久层中相关方法

1.根据Id查询

    <select id="findById" parameterType="java.lang.Integer" resultType="com.wink.domain.User">
        select * FROM USER where id = #{id}
    </select>
  • resultType属性:用于指定结果集的类型
    parameterType属性:用于指定传入参数的类型
  • sql 语句中使用#{}字符:
    它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。

2.保存操作

    <insert id="saveUser" parameterType="com.wink.domain.User">
        <!--配置插入操作之后,获取插入数据的id-->
        <selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int" >
            select last_insert_id()
        </selectKey>
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>
  • #{}中内容的写法:
    由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。 它用的是 ognl 表达式。

ognl表达式

它是 apache 提供的一种表达式语言,全称是: Object Graphic Navigation Language 对象图导航语言 它是按照一定的语法格式来获取数据的。 语法格式就是使用 #{对象.对象}的方式
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username。

  • 此处的selectKey并非必须,是为了演示新增用户后,返回当前新增用户的id值,因为id是由数据库的自动增长来实现的,所以就相 当于我们要在新增后将自动增长 auto_increment 的值返回。
    在这里插入图片描述
    3.更新操作
    <update id="updateUser" parameterType="com.wink.domain.User">
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id = #{id}
    </update>

4.删除操作

    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id=#{uid}
    </delete>

5.模糊查询

    <select id="findByName" parameterType="String" resultType="com.wink.domain.User">
        select * from user where username like #{username}
    </select>
  • 若使用上述配置方法,我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”执行效果如下:
    在这里插入图片描述
  • 这里有两种配置方法,另一种是 select * from user where username like ‘%${value}%’
    在这里插入图片描述
    可以发现,我们在程序代码中就不需要加入模糊查询的匹配符%了,这两种方式的实现效果是一样的,但执行 的语句是不一样的。

{}和${}的区别

  • #{}表示一个占位符,${}表示拼接sql串

  • 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。

  • 通过$ {}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换, $ {}可以接收简 单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value

    6.聚合函数

    扫描二维码关注公众号,回复: 9467043 查看本文章
    <select id="findtotal" resultType="Integer">
        select count(*) from user
    </select>
  • 下面是IUSerDaoMapper.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.wink.dao.IUserDao">
    <!-- 查询所有-->
    <select id="findAll" resultType="com.wink.domain.User">
        select * FROM USER
    </select>

    <!--根据Id查询-->
    <select id="findById" parameterType="java.lang.Integer" resultType="com.wink.domain.User">
        select * FROM USER where id = #{id}
    </select>

    <!-- 保存用户-->
    <insert id="saveUser" parameterType="com.wink.domain.User">
        <!--配置插入操作之后,获取插入数据的id-->
        <selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int" >
            select last_insert_id()
        </selectKey>
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
    </insert>

    <!-- 更新用户-->
    <update id="updateUser" parameterType="com.wink.domain.User">
        update user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id = #{id}
    </update>

    <!--删除用户-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id=#{uid}
    </delete>

    <!-- 根据名称模糊查询-->
    <select id="findByName" parameterType="String" resultType="com.wink.domain.User">
        select * from user where username like #{username}
        <!--select * from user where username like '%${value}%'-->
    </select>

    <!-- 查询总记录数-->
    <select id="findtotal" resultType="Integer">
        select count(*) from user
    </select>
</mapper>

1.4 编写测试类

  • MybatisTest.java
public class MybatisTest {

    private InputStream is;
    private SqlSession Sqlsession;
    private IUserDao userDao;

    @Before//用在测试方法执行之前
    public void init() throws Exception{
        //1.读取配置文件,生成字节流
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.获取SqlSession对象
        Sqlsession = factory.openSession();
        //4.获取dao的代理对象
        userDao = Sqlsession.getMapper(IUserDao.class);
    }

    @After//用在测试方法执行之后
    public void destory() throws Exception{
        //提交事务(不然操作不能正常执行)
        Sqlsession.commit();
        //6.释放资源
        Sqlsession.close();
        is.close();
    }

    @Test
    public void TestfindAll() {
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void TestfindById(){
        System.out.println(userDao.findById(1));
    }

    @Test
    public void TestsaveUser(){
        User user = new User();
        user.setUsername("保存");
        user.setBirthday(new Date());
        user.setSex("男");
        user.setAddress("南京");
        System.out.println("保存之前"+user);
        //5.执行保存方法
        userDao.saveUser(user);
        System.out.println("保存之后"+user);
    }

    @Test
    public void TestupdateUser(){
        User user = userDao.findById(1);
        user.setSex("女");
        userDao.updateUser(user);
    }

    @Test
    public void TestdeleteUser(){
        userDao.deleteUser(9);
    }

    @Test
    public void TestfindByName(){
        List<User> users = userDao.findByName("%王%");
//        List<User> users = userDao.findByName("王");
        for (User user : users) {
            System.out.println(user);
        }
    }
    
    @Test
    public void Testfindtotal(){
        System.out.println("总条数="+userDao.findtotal());
    }
}
  • 注意:
    1.我们在实现增删改时一定要去控制事务的提交,Sqlsession.commit();否则会出现程序通过运行,却未改变数据
    在这里插入图片描述

2.SqlMapConfig.xml配置文件

2.1 配置内容和顺序

-properties(属性)
	--property
-settings(全局配置参数)
	--setting
-typeAliases(类型别名) 
	--typeAliase
	--package
-typeHandlers(类型处理器) 
-objectFactory(对象工厂) 
-plugins(插件) 
-environments(环境集合属性对象)  
	--environment(环境子属性对象)   
		---transactionManager(事务管理)   
		---dataSource(数据源)
 -mappers(映射器)  
 	--mapper  
 	--package 

2.2 properties属性

<!-- 配置properties
    可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息
    resource属性: 常用的
        用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。
    url属性:
        是要求按照Url的写法来写地址
        URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
        它的写法:
            http://localhost:8080/mybatisserver/Servlet01
            协议      主机     端口       URI
        URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
-->

2.3 typeAliases(类型别名)

使用typeAliases配置别名,它只能配置实体类中类的别名
    <typeAliases>
        typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就不再区分大小写
        <typeAlias type="com.wink.domain.User" alias="user"></typeAlias>
         /*用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写
        	<package name="com.wink.domain"></package>
        */
    </typeAliases>

2.4 mappers(映射器)

  • < mapper resource=" ">< /mapper>
    使用相对类路径的资源,如:
    < mapper resource=“com/wink/dao/IUserDaoMapper.xml”></ mapper>
  • < mapper class=""></ mapper>
    使用接口类路径,如:
    < mapper class=“com.wink.dao.UserDao”></ mapper>
    注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
  • < package name=" "/>
    注册指定包下的所有 mapper 接口 ,如:
    < package name=“com.wink.mybatis.mapper”/>
    注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

3.Mybatis的参数深入

3.1 parameterType配置参数

  • 上面案例可以知道SQL 语句传参,使用标签的 parameterType 属性来设定。该属性的取值可以使基本类型,引用类型(例如:String类型),还可以是实体类型(POJO类),同时也可以使用实体类的包装类。
    注意: 基本类型和 String 我们可以直接 写类型名称 ,也可以使用包名 . 类名的方式 ,例如 : java.lang.String
    实体类类型,目前只能使用全限定类名
    是因为mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名, 而我们的是实体类并没有注册别名,所以必须写全限定类名

3.2 传递pojo包装对象

  • 开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件,这时可以使用包装对象传递输入参数。 Pojo 类中包含 pojo。
    通过下面案例展示:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。
  • 编写QueryVo.java
public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}
  • 编写持久层接口
	public interface IUserDao{
    	List<User> findUserByVo(QueryVo vo);
    }
  • 持久层接口的映射文件
    <select id="findUserByVo" parameterType="com.wink.domain.QueryVo" resultType="com.wink.domain.User">
        select * from user where username like #{user.username}
    </select>
  • 测试包装类作为参数
    @Test
    public void testFindByQueryVo() {
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUsername("%王%");
        vo.setUser(user);
        List<User> users = userDao.findUserByVo(vo);
        for(User u : users) {
            System.out.println(u);  }
    }
  • 结果如下

在这里插入图片描述

发布了9 篇原创文章 · 获赞 1 · 访问量 275

猜你喜欢

转载自blog.csdn.net/qq_41460383/article/details/104417789