MyBatis框架安排

2. 第二天:

1. MyBatis的增删改查操作(操作配置文件SqlMapConfig.xml)

  1. 在SqlMapConfig.xml中向数据库中增加条目

    <!-- 插入数据 -->
    <!-- parameterType="com.liuzeyu.domin.User"参数类型,通过反射为#{username}...赋值-->
    <insert id="save" parameterType="com.liuzeyu.domin.User">
        <!-- 插入数后返回id,keyProperty="id"对应实体类属性,keyColumn="id"对应数据库列名,AFTER:操作最后执行-->
        <selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int">
        <!-- SELECT last_insert_id()  返回刚刚插入的数据id-- >
            SELECT last_insert_id() 
        </selectKey>
        insert into user (username,birthday,sex,address)VALUES (#{username},#{birthday},#{sex},#{address})
    </insert>
    
  2. 在SqlMapConfig.xml中向数据库中删除条目

    <!-- 根据id删除-->
    <delete id="delete" parameterType="int">
        delete from user where id=#{uid}
    </delete>
    
  3. 在SqlMapConfig.xml向数据库中修改条目

    <!-- 更新数据 -->
    <update id="update" parameterType="com.liuzeyu.domin.User">
        UPDATE user SET username=#{username},birthday=#{birthday},address=#{address},sex=#{sex} where id=#{id}
    </update>
    
  4. 在SqlMapConfig.xml向数据库中查询条目

        <!-- 根据id查找一个 -->
        <select id="findById" resultType="com.liuzeyu.domin.User" parameterType="int">
            select * from user where id=#{uid}
        </select>
        <!-- 根据name查找集合 -->
        <select id="findByName" resultType="com.liuzeyu.domin.User" parameterType="string">
              select * from user where username like #{string}
        <!-- select * from user where username like '%${value}%' -->
      </select>
      <!-- 查询总记录数-->
        <select id="findTotal" resultType="int">
            SELECT count(*) FROM USER
        </select>
    

测试类:

```
package com.liuzeyu.test;

import com.liuzeyu.dao.IUserDao;
import com.liuzeyu.domin.User;
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 java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

public class Test {
    private InputStream is = null;
    private IUserDao userDao = null;
    private  SqlSession session = null;
    /**
     * 初始化
     * @throws IOException
     */
    @Before  //测试开始前执行
    public void init() throws IOException {
        //1.解析xml配置文件
        is = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.构建工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
        //3.工厂生产SqlSession对象
        session = factory.openSession();
        //4.创建代理Dao的对象
        userDao = session.getMapper(IUserDao.class);
    }
    @After //测试结束后执行
    public void destory(){
        session.commit();
        //7.释放资源
        if( session != null){
            session.close();
        }
        if( is != null){
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    @org.junit.Test
    public void testSelect() throws IOException {
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        //6.遍历对象
        for (User user : users) {
            System.out.println(user);
        }
    }
    @org.junit.Test
    public void testSave() throws IOException {
        User user = new User();
        user.setUsername("liuzeyu");
        user.setBirthday(new Date());
        user.setAddress("莆田");
        user.setSex("男");
        System.out.println("保存前:"+user);
        userDao.save(user);
        System.out.println("保存后:"+user);
    }
    @org.junit.Test
    public void testUpdate() throws IOException {
        User user = new User();
        user.setId(48);
        user.setUsername("duyangting");
        user.setBirthday(new Date());
        user.setAddress("厦门");
        user.setSex("女");
        userDao.update(user);
    }
    @org.junit.Test
    public void testDelete() throws IOException {
        userDao.delete(46);
    }
    @org.junit.Test
    public void testFindOne() throws IOException {
        User user = userDao.findById(42);
        System.out.println(user);
    }

    @org.junit.Test
    public void testFindOneByName() throws IOException {
           List<User> users = userDao.findByName("%王%");//使用的是PreparedStatement的查询方式,Preparing: select * from user where username like ?
//        List<User> users = userDao.findByName("王"); //使用的是拼接字符串的查询方式,Preparing: select * from user where username like '%王%'
        for (User user : users) {
            System.out.println(user);
        }
    }
    @org.junit.Test
    public void testFindTotal() throws IOException {
        int total = userDao.findTotal();
        System.out.println(total);
    }
}
```

2. 多个对象组成一个查询条件

  1. 将user 对象使用类QueryStringVo包装
    /**
     * 将查询条件封装到一个类中
     */
    public class QueryStringVo {
        private User user;
    
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    }
    
  2. 在SqlMapConfig.xml向数据库中查询条件
    </select>
    <!-- 根据queryStringVo查询-->
    <select id="findByVo" resultType="com.liuzeyu.domin.User" parameterType="com.liuzeyu.vo.QueryStringVo">
        select * from user where username like #{user.username}
        <!-- select * from user where username like '%${value}%' -->
    </select>
  1. 测试函数(结果与模糊查询一致)

       @org.junit.Test
        public void testFindOneByVo() throws IOException {
            QueryStringVo vo = new QueryStringVo();
            User user = new User();
            user.setUsername("%王%");
            vo.setUser(user);
            List<User> users = userDao.findByVo(vo);//使用的是PreparedStatement的查询方式,Preparing: select * from user where username like ?
    
            for (User u : users) {
                System.out.println(u);
            }
        }
    

3. OGNL表达式介绍

OGNL :Object Graphic Navigation Lanuage (对象图导航语言)
它是通过对象取值方法来获取数据的,在写法上把类似JavaBean的get方法给删掉了。

类中的写法 user.getUsername
OGNL表达式:user.username

例如上面的

<insert id="save" parameterType="com.liuzeyu.domin.User">
    insert into user (username,birthday,sex,address)VALUES (#{username},#{birthday},#{sex},#{address})
</insert>

由于parameterType属性已经提供了类的路径,则要获取values的username需要之需要写User类的属性即可#{username},否则需要写user.username
类似于:

 <!-- 根据queryStringVo查询-->
 <select id="findByVo" resultType="com.liuzeyu.domin.User" parameterType="com.liuzeyu.vo.QueryStringVo">
     select * from user where username like #{user.username}
     <!-- select * from user where username like '%${value}%' -->
 </select>

4. 数据库表字段和实体类属性不一致问题

解决方法有两个:
方法一:通过对发送的sql语句字段名取别名来处理

 <!-- 打印user表数据 -->
 <select id="findAll" resultType="com.liuzeyu.domin.User">
     <!-- 取别名来和实体类产生关系 -->
     <!--SELECT id as userId,username as userName,address as userAddress,birthday as userBirthday ,sex as userSex from user -->
 </select>

其中userId,userName,userAddress,userBirthday ,userSex 是实体类的属性。
对应的数据库列名:id,username,address,birthday,sex
这样查询出来的结果的字段名就是userId,userName,userAddress,userBirthday ,userSex ,此时就与实体类一一对应了。

方法二:通过配置文件来实现:

 <!-- 配置查询的列名和实体类直接的对应关系-->
 <resultMap id="userMap" type="com.liuzeyu.domin.User">
     <!-- 主键id对应,property="userId"实体类属性, column="id"数据库列字段名-->
     <id property="userId" column="id"/>
     <!-- 非主键字段的对应关系-->
     <result property="userName" column="username"/>
     <result property="userAddress" column="address"/>
     <result property="userBirthday" column="birthday"/>
     <result property="userSex" column="sex"/>
 </resultMap>

在操作数据库的标签内添加resultMap属性引用即可,如:

    <!-- 打印user表数据 -->
    <select id="findAll" resultType="com.liuzeyu.domin.User" resultMap="userMap">
         SELECT * from USER
    </select>

方法一比方法二的执行效率更高,但是方法二比方法一开发效率更高,就是说当项目比较大时,使用方法二会提高开发效率。

5. 优化主配置文件

  1. 引用外部连接数据库的连接信息
    在主配置文件下< configuration >标签内部添加properties 的resource配置或url配置引用外部配置文件
    <!-- 配置标签内部的属性连接数据库的信息,可以通过引用外部资源文件-->
    <!--1. resource的配置方式-->
	    <!--<properties resource="jdbcConfig.properties">-->
	    <!--</properties>-->
    <!--2. url的配置方式-->
        <!--
        url 与 uri的区别
        url:uniform resource locator 统一资源定位  唯一标识一个资源的位置
            写法:
            协议://主机:端口/uri
            http://localhost:80/servlet/index
        uri:uniform resource  Identifier 统一资源标识  在应用中唯一定位一个资源
        -->
	    <properties url="file:\\\C:\Users\lzy\IdeaProjects\day02_mybatis_modify\src\main\resources\jdbcConfig.properties">
	
	    </properties>

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis
jdbc.username=root
jdbc.password=809080

之后再JDBC的连接池里面以$获取实际配置文件中的值

<!-- JDBC连接池 -->
<dataSource type="POOLED">
    <property name="driver" value="${jdbc.driver}"/>
    <property name="url" value="${jdbc.url}"/>
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
</dataSource>
  1. 为标签属性取别名
    取完别名后,可以再映射配置文件中直接使用
    <!--自定义为配置文件取别名-->
    <typeAliases>
        <!--<typeAlias type="com.liuzeyu.domin.User" alias="user"/>-->
        <package name="com.liuzeyu.domin"/>
    </typeAliases>

<mark>使用typeAlias 标签去别名和package有一个区别?</mark>
typeAlias 指定type对象后,alias是别名,并且再映射配置文件中使用它可以不区分大小写,如:

package标签是指定取别名的包,当指定后,该包下<mark>所有的实体类</mark>都会被指定别名,并且类名就是别名,不再区分大小写。

  1. 简化主配置的映射接口配置

        <mappers>
            <!--<mapper resource="com/liuzeyu/dao/IUserDao.xml"></mapper>-->
            <package name="com.liuzeyu.dao"></package>
        </mappers>
    

    上面这种配置有一个好处是,再package标签下指定dao接口所在的包,就可以不用再写mapper以及class和resource属性了,它可以直接找到映射配置文件