Mybatis(二)之注解在分析,CRUD,参数,返回值

自定义Mybatis定义的开发流程图

Mybatis(二)之注解在分析,CRUD,参数,返回值_第1张图片

基于注解的自定义在分析

主配置文件主要用到了两种配置信息
一种是连接数据库的
在这里插入图片描述
一种是映射信息的
Mybatis(二)之注解在分析,CRUD,参数,返回值_第2张图片

xml获取映射配置
Mybatis(二)之注解在分析,CRUD,参数,返回值_第3张图片
注解获取的信息
Mybatis(二)之注解在分析,CRUD,参数,返回值_第4张图片
其中注解中封装map的key
Mybatis(二)之注解在分析,CRUD,参数,返回值_第5张图片
注解获取resultType
Mybatis(二)之注解在分析,CRUD,参数,返回值_第6张图片

Mybatis的环境搭建

1导入以下常用依赖和配置

<packaging>jar</packaging>
<dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

2 在main/resources文件夹中导入log4j.properties

3 创建实体类

public class User implements Serializable{
        private Integer id;
        private String username;
        private String address;
        private String sex;
        private Date birthday;

    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 String getAddress() {
        return address;
    }

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

    public String getSex() {
        return sex;
    }

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

    public Date getBirthday() {
        return birthday;
    }

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

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

4 创建主配置文件

<?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>
    <!--配置环境-->
<environments default="mysql">
    <!--配置mysql的环境-->
    <environment id="mysql">
        <!--配置事务-->
        <transactionManager type="JDBC"></transactionManager>
        <!--配置连接池-->
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"></property>
            <property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
            <property name="username" value="root"></property>
            <property name="password" value="xgh961120"></property>
        </dataSource>
    </environment>
</environments>


    <mappers>
        <mapper resource="cn/tju/dao/IUserDao.xml"></mapper>
    </mappers>



</configuration>

5 创建接口的映射文件

记住在resources文件夹下创建多级目录一定要分级创建不能一次性直接用点创建
在resources目录下创建cn/tju/dao/IUserDao.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="cn.tju.dao.IUserDao">
    <!--查询所有-->
    <select id="findAll" resultType="cn.tju.domain.User">
        select * from user;
    </select>
</mapper>

6 创建IUserDao接口

public interface IUserDao  {
    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();
}

7 创建测试类

/**
 * 测试Mybatis的crud操作
 */
public class Mybatis {

   @Test
    public void testFindAll() throws IOException {
       //1 读取配置文件,生成字节输入流
       InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
       //2 获取SqlSessionFactory
       SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
       //3获取SqlSession对象
       SqlSession sqlSession = factory.openSession();
       //4获取dao代理对象
       IUserDao userDao = sqlSession.getMapper(IUserDao.class);
       List<User> users = userDao.findAll();
       for (User user : users) {
           System.out.println(user);
       }
       sqlSession.close();
       in.close();
   }
}

Mybatis的CRUD-保存操作

IUserDao.java

public interface IUserDao  {
    /**
     * 保存用户
     * @return
     */
    void saveUser(User user);
}

IUserDao.xml,,ParameterType中封装对应实体类的全路径,values(#{对应实体类的属性})

<mapper namespace="cn.tju.dao.IUserDao">
    <!--保存用户-->
    <insert id="saveUser" parameterType="cn.tju.domain.User">
        insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday});
    </insert>
</mapper>
测试类注意一定要提交事务,sqlSession.commit();
@Test
    public void testSaveUser() throws IOException {
       //1 读取配置文件,生成字节输入流
       InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
       //2 获取SqlSessionFactory
       SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
       //3获取SqlSession对象
       SqlSession sqlSession = factory.openSession();
       //4获取dao代理对象
       IUserDao userDao = sqlSession.getMapper(IUserDao.class);
       Date date =new Date(1000);

       userDao.saveUser(new User("辛国华","tju","1",date));
      sqlSession.commit();

       sqlSession.close();
       in.close();
   }

Mybatis的CRUD-删除操作

IUserDao.java
public interface IUserDao {
    /**
     * 根据Id删除用户
     * @param userId
     */
    void deleteUser(Integer userId);
}

IUserDao.xml

<mapper namespace="cn.tju.dao.IUserDao">
    <!-- 删除用户因为deleteUser的参数是Integer所以parameterType是Integer,方法中只有一个参数占位符可以叫任意名字-->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id = #{uid}
    </delete>
</mapper>

测试

/**
 * 测试删除操作
 */
@Test
public void testDelete(){
    //执行删除方法
    userDao.deleteUser(48);
}

Mybatis的CRUD-查询一个操作和模糊查询

IUserDao.java
/**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);

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

IUserDao.xml

 <!-- 根据id查询用户,一个参数占位符随便写#{uid} -->
    <select id="findById" parameterType="INT" resultType="cn.tju.domain.User">
        select * from user where id = #{uid}
    </select>

    <!-- 根据名称模糊查询,一个参数占位符随便写#{name} -->
    <select id="findByName" parameterType="string" resultType="cn.tju.domain.User">
          select * from user where username like #{name}
   </select>

测试类

 @Test

public void testFindOne(){
    //执行查询一个方法
    User  user = userDao.findById(50);
    System.out.println(user);
}

/**
 * 测试模糊查询操作
 */
@Test
public void testFindByName(){
    //5.执行查询一个方法
    List<User> users = userDao.findByName("%王%");
    for(User user : users){
        System.out.println(user);
    }
}

Mybatis的CRUD-查询返回一行一列

IUserDao.java
 /**
     * 查询总用户数
     * @return
     */
    int findTotal();
IUserDao.xml
<!-- 获取用户的总记录条数 -->
    <select id="findTotal" resultType="int">
        select count(id) from user;
    </select>
/**
     * 测试查询总记录条数
     */
    @Test
    public void testFindTotal(){
        //5.执行查询一个方法
        int count = userDao.findTotal();
        System.out.println(count);
    }

Mybatis的CRUD-保存操作细节,获取保存数据的id

IUserDao.xml

<!-- 保存用户 -->
    <insert id="saveUser" parameterType="user">
        <!-- 配置插入操作后,获取插入数据的id,kerProperty对应实体类,keyColumn对应表的列名,什么时候获取插入的id,在插入之后 -->
        <selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
    </insert>
  /**
     * 测试保存操作
     */
    @Test
    public void testSave(){
        User user = new User();
        user.setUserName("modify User property");
        user.setUserAddress("北京市顺义区");
        user.setUserSex("男");
        user.setUserBirthday(new Date());
        //保存之前没有设置id值,id值为null
        System.out.println("保存操作之前:"+user);
        //执行保存方法之后
        userDao.saveUser(user);
      //保存设置之后id值设置为上面插入,数据库返回的id值
        System.out.println("保存操作之后:"+user);
    }

Mybatis中参数的深入–使用实体类的包装对象作为查询条件

1 传递简单类型

比如id的int,模糊查询中的String

2 传递pojo对象

也就是JavaBean实体类对象
Mybatis使用ognL表达式解析对象字段的值,#{}或者${}的值为pojo属性名称

OGNL表达式
Object graphc Navigation Language对象图导航语言
它是通过对象的取值方法来获取数据。在写法上把get给省略了
比如:我们获取用户的名称
类中的写法:user.getUsername();
OGNL表达式的写法:user.username

  • mybatis中为什么能直接写username,而不用user.呢?
    因为在pramaterType中已经提供了属性所属的类,所以不需要写对象名
把多个对象封装到QueryVo中,这样查询条件就可以结合多个对象

新建 cn.tju/dao.QueryVo

public class QueryVo {
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

IUserDao.xml

 <!--根据queryVo的条件查询用户,直接使用user,因为user是QueryVo的属性,user在.获得user的属性-->
<select id="findUserByVo" parameterType="cn.tju.domain.QueryVo" resultType="cn.tju.domain.User">
select * from user where username like #{user.username}
 </select>

测试

 /**
     * 测试使用QueryVo作为查询条件
     */
    @Test
    public void testFindByVo(){
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUserName("%王%");
        vo.setUser(user);
        //5.执行查询一个方法
        List<User> users = userDao.findUserByVo(vo);
        for(User u : users){
            System.out.println(u);
        }
    }

Mybatis中返回值深入,调整实体类属性

比如说User实体类的属性 userId,userName,userAddress,userSex, userBirthday
数据库user表的列名id ,username,address ,sex,birthday
当实体类属性与数据库属性不对应时解决办法

  1. 修改sql语句将列名用别名替代
    select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;
    这样能查询出来的列名又和实体类达成了一致

  2. 建立映射的标签ResultMap,查询的结果封装到UserMap中实现数据库类名改变在封装到实体类的目的

  <resultMap id="userMap" type="uSeR">
        <!-- 主键字段的对应 -->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userAddress" column="address"></result>
        <result property="userSex" column="sex"></result>
        <result property="userBirthday" column="birthday"></result>
    </resultMap>
<select id="findAll" resultMap="userMap">
        <!--select id as userId,username as userName,address as userAddress,sex as userSex,birthday as userBirthday from user;-->
        select * from user;
    </select>

Mybatis中编写dao实现类的使用方式

用户的持久层接口

public interface IUserDao {

    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();

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

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

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

    /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);

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

    /**
     * 查询总用户数
     * @return
     */
    int findTotal();

}

新建dao的实现类

public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory){
        this.factory = factory;
    }

    @Override
    public List<User> findAll() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("cn.tju.dao.IUserDao.findAll");//参数就是能获取配置信息的key
        //3.释放资源
        session.close();
        return users;
    }

    @Override
    public void saveUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现保存
        session.insert("cn.tju.dao.IUserDao.saveUser",user);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    @Override
    public void updateUser(User user) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现更新
        session.update("cn.tju.dao.IUserDao.updateUser",user);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    @Override
    public void deleteUser(Integer userId) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用方法实现更新
        session.update("cn.tju.dao.IUserDao.deleteUser",userId);
        //3.提交事务
        session.commit();
        //4.释放资源
        session.close();
    }

    @Override
    public User findById(Integer userId) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询一个
        User user = session.selectOne("cn.tju.dao.IUserDao.findById",userId);
        //3.释放资源
        session.close();
        return user;
    }

    @Override
    public List<User> findByName(String username) {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("cn.tju.dao.IUserDao.findByName",username);
        //3.释放资源
        session.close();
        return users;
    }

    @Override
    public int findTotal() {
        //1.根据factory获取SqlSession对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询一个
        Integer count = session.selectOne("cn.tju.dao.IUserDao.findTotal");
        //3.释放资源
        session.close();
        return count;
    }
}

测试类

public class MybatisTest {

    private InputStream in;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws Exception{
        //1.读取配置文件,生成字节输入流
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.获取SqlSessionFactory
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //3.使用工厂对象,创建dao对象
        userDao = new UserDaoImpl(factory);
    }

    @After//用于在测试方法执行之后执行
    public void destroy()throws Exception{
        //6.释放资源
        in.close();
    }

    /**
     * 测试查询所有
     */
    @Test
    public void testFindAll(){
        //5.执行查询所有方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }

    }
    /**
     * 测试保存操作
     */
    @Test
    public void testSave(){
        User user = new User();
        user.setUsername("dao impl user");
        user.setAddress("北京市顺义区");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("保存操作之前:"+user);
        //5.执行保存方法
        userDao.saveUser(user);

        System.out.println("保存操作之后:"+user);
    }

    /**
     * 测试更新操作
     */
    @Test
    public void testUpdate(){
        User user = new User();
        user.setId(50);
        user.setUsername("userdaoimpl update user");
        user.setAddress("北京市顺义区");
        user.setSex("女");
        user.setBirthday(new Date());

        //5.执行保存方法
        userDao.updateUser(user);
    }

    /**
     * 测试删除操作
     */
    @Test
    public void testDelete(){
        //5.执行删除方法
        userDao.deleteUser(54);
    }

    /**
     * 测试删除操作
     */
    @Test
    public void testFindOne(){
        //5.执行查询一个方法
        User  user = userDao.findById(50);
        System.out.println(user);
    }

    /**
     * 测试模糊查询操作
     */
    @Test
    public void testFindByName(){
        //5.执行查询一个方法
        List<User> users = userDao.findByName("%王%");
        for(User user : users){
            System.out.println(user);
        }
    }

    /**
     * 测试查询总记录条数
     */
    @Test
    public void testFindTotal(){
        //5.执行查询一个方法
        int count = userDao.findTotal();
        System.out.println(count);
    }
}

Mybatis中使用Dao实现类的执行过程分析

Mybatis(二)之注解在分析,CRUD,参数,返回值_第7张图片

在Dao的实现类中重写了IUserDao接口中的findAll,SaveUser,updateUser,deleteUser,fineById方法
五个方法中session操作的方法是不一样的

Mybatis中使用Dao实现类查询方法的执行过程分析
Mybatis(二)之注解在分析,CRUD,参数,返回值_第8张图片
通过调试,发现在实现类中调用的selectList方法的是DefaultSqlSession对象(sqlSession的实现类)
Mybatis(二)之注解在分析,CRUD,参数,返回值_第9张图片

如何去找sqlSession的实现类DefaultSqlSession
由接口找相应的实现类
Mybatis(二)之注解在分析,CRUD,参数,返回值_第10张图片
Mybatis(二)之注解在分析,CRUD,参数,返回值_第11张图片
Mybatis(二)之注解在分析,CRUD,参数,返回值_第12张图片
最后选中选择上方的代码,进入实现类

进入实现类发现SelectList有三个方法,实际上是调用最后一个selectList(三个参数)
Mybatis(二)之注解在分析,CRUD,参数,返回值_第13张图片

selectList(三个参数)实际上时调用executor.query()方法
进入query方法发现又是Executor接口的方法
只能继续打断点找Executor的实现类Mybatis(二)之注解在分析,CRUD,参数,返回值_第14张图片

打断点发现是CatchingExcutor实现类
同样的方法进入实现类找到query方法,发现四个参数的query方法,调用6个参数的方法
6个参数的方法query在调用delegate.query

通过调试发现delegate是一个SimpleExecutor
Mybatis(二)之注解在分析,CRUD,参数,返回值_第15张图片
在Executor找SimpleExecutor实现类进入代码
发现没有query方法只有doQuery方法,只能到其父类baseExecutor找query

发现baseExecutor找query,其调用queryFromDatabase(),然后调用doQuery------>抽象方法(被SimpleExecutor实现,其实最后执行的就是doQuery方法)

回到SimpleExecutor的doQuery(重写父类的抽象方法)
调用 handler.query
Mybatis(二)之注解在分析,CRUD,参数,返回值_第16张图片
handeler是Rootinghandler
找到接口statementHandler找到其实现类Rootinghandler进入找到query方法

Rootinghandler中的query方法调用delegate.query
在这里插入图片描述
调试发现delegate是PreparedStatementHander
找到PreparedStatementHander实现类进去

最后结果
JDBC prepareStatement对象
Mybatis(二)之注解在分析,CRUD,参数,返回值_第17张图片

Mybatis中使用代理Dao的执行过程分析
Mybatis(二)之注解在分析,CRUD,参数,返回值_第18张图片
从sqlSession的获取dao的代理对象入手
userDao =sqlSession.getMapper(IUserDao.class)

进入sqlSession接口,找sqlSession的实现类DefaultSqlSession
进入DefaultSqlSession代码里getMapper()方法发现configuration.getMapper();

进入Configuration类里的getMapper();代码里mapperRegistry.getMapper(type,sqlSession);

进入mapperRegistry里找到getMapper方法里 代码里mapperProxyFactory,newInstance(sqlSession)

进入mapperProxyFactory类里的newInstance方法
发现public T newInstance(SqlSession sqlSession)中调用同一个类中的newInstace(mapperProxy)方法
进入protected T newInstance(MapperProxy mapperProxy){
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(),new Class[]{mapperInterface},mapperProxy)//正是动态代理
}

关注动态代理的第三个参数,mapperProxy这个类究竟是什么?
进入类mapperProxy发现类实现了InvocationHandler的接口,并且有invoke方法
在invoke方法中有mapperMethod.execute(sqlSession,args)

进入mapperMethod类找到execute方法,方法里调用sqlSession的insert,update,delete和executeForMany方法
executeForMany调用SqlSession的selectList方法

properties标签的使用及细节

配置properties

可以在标签内部配置连接数据库的信息。也可以通过属性引用外部配置文件信息

方式一

在配置文件内部使用properties标签,配置时直接使用proprety

 <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"></property>
        <property name="username" value="root"></property>
        <property name="password" value="1234"></property>
</properties>
 <!--配置连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"></property>
                <property name="url" value="${url}"></property>
                <property name="username" value="${username}"></property>
                <property name="password" value="${password}"></property>
            </dataSource>

方式二

用properties文件配置

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

properties标签配置properties位置得两种方式

  • resource属性: 常用的
    用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下(也就是main/resource路径下)。
  • url属性:
    是要求按照Url的写法来写地址
    URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
    它的写法:
    http://localhost:8080/mybatisserver/demo1Servlet
    协议 主机 端口 URI
    URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。
    在配置文件中propreties属性url指明properties文件位置
 <properties url="file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.properties">
    </properties>

typeAliases标签和package标签

 <typeAliases>
        <!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写 
        <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->

        <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
        <package name="com.itheima.domain"></package>
 </typeAliases>
 <!-- 配置映射文件的位置 -->
    <mappers>
        <!--当配置了package就不再每一个接口得配置文件单独指定<mapper resource="com/itheima/dao/IUserDao.xml"></mapper>-->
        <!-- package标签是用于指定dao接口所在的包,当指定了之后就不需要在写mapper以及resource或者class-->
        <package name="com.itheima.dao"></package>
    </mappers>

你可能感兴趣的:(JAVA框架)