SSM--MyBatis学习

一、MyBatis的概述

Mybatis 是一个继承了传统的JDBC技术的dao层框架(持久层框架),可以使开发者只关注sql语句的本身而无需过多地考虑加载数据库驱动,创建连接,创建Statement 等复杂的过程。
Mybatis 通过xml或者注解的方式将要执行的statement配置起来,并通过java对象和statement中的sql的动态参数进行映射生成最终执行的sql语句,最后由Mybatis 框架将封装好的java对象返回。
采用ORM思想解决了实体和数据库的映射问题,对JDBC 进行了封装,屏蔽了jdbc api底层访问的细节。
前身是ibatis,关键是ORM(Object Relation Map)对象关系映射

二、MyBatis的环境搭建(idea创建)

1.新建一个Maven工程(不选webapp),域名com.xxx,工程名:mybatis_1

注意:解决maven工程创建过慢一般可以在创建的时候添加: archetypeCatalog : internal
在这里插入图片描述

2.在数据库中新建一个user表。

在这里插入图片描述

3.在idea中打开刚创建的maven项目的pom.xml文件,添加打包方式和架包支持:

首先添加的是一个打包方式,下边添加的是mybatis的基础架包
继续添加架包支持:添加mysql,log4j,以及单元测试的架包支持
完整代码:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xxx</groupId>
    <artifactId>mybatis_1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.48</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

三、简单介绍一个入门案例

接着上边的搭建好的环境实现一个简单的案例,先创建两个新的包:
在这里插入图片描述
然后再domain包中创建一个实体类User,直接贴代码了:


    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String 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 "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

然后再在dao包创建一个UserDao接口:(后边就由mybatis来管理,并实现接口的功能了,不用写实现类)

public interface UserDao {
    /**
     * 查询所有的操作
     */
    // @Select("select * from user") 这是使用注解,不使用xml映射文件配置的方式(这种方式不用写UserDao.xml)
    List<User> findAll();
}

然后再在resources包下边新建一个SqlMapConfig.xml的住配置文件,用于存放搭建数据库连接等重要信息的基础环境的信息,和指定相应的映射文件,是一个mybatis全局环境配置包。详细的代码如下:

<?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>
    <!-- 配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境,这里的id需要和上边的定义的默认值保持一致-->
        <environment id="mysql">
            <!-- 配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!-- 配置数据库的四个基本信息,驱动类型,url,username,password-->
                <!-- 有了这个配置就能连接数据库,创建Connection对象-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/test_mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 指定映射文件的配置,映射配置文件指的是每个dao独立的配置文件 com/xxx/dao/UserDao.xml
        如果使用注解的方式来配置的话,此处应该使用class属性指定北朱解的dao的全限定名 com.xxx.dao.UserDao-->
    <mappers>
    <!-- 有了它就能映射配置信息-->
        <mapper resource="com/xxx/dao/UserDao.xml"/>
    </mappers>
</configuration>

然后在resources下继续新键包:com.xxx.dao,在此包里新建一个UserDao.xml(就是为了和上边的UserDao的结构都保持一致,必须一致才能正确执行!),UserDao.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.xxx.dao.UserDao">
    <!--配置查询所有的接口实现,注意这里的id必须是前边java接口中定义的接口方法名称!
    	resultType:告诉mybatis把返回的数据结果存到怎样的结果集中
    	着实质性SQL的语句,可以获取到PrepareStatement-->
    <select id="findAll" resultType="com.xxx.domain.User">
        select * from user
    </select>
</mapper>

至此,所有的包结构如图:
在这里插入图片描述
到这里完成的工作包括:
1.创建Maven工程,并导入相应的架包支持
2.创建一个实体类和一个实现查询的dao接口
3.创建一个住配置文件,存放环境配置的相关信息SqlMapConfig.xml
4.创建映射配置文件:UserDao.xml

开始创建一个测试类来测试:
先将log4j.properties导进resources下,然后在test测试包下新建一个包com.xxx.test,新建一个java文件:MyBatisTest.java:

public class MyBatisTest {

    /**
     * mybatis的入门案例
     * @param args
     */
    public static void main(String[] args) throws IOException {
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//读取配置文件的时候,一般使用类加载器或者ServletContext对象的getRealPath()
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//创建工厂的时候,mybatis的使用了”构建者模式“,使使用者直接调用方法即可拿到对象
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession sqlSession = factory.openSession();//生产sqlSession使用了工厂模式,降低了类之间的依赖关系
        //4.使用SqlSession创建Dao接口的代理对象
        UserDao dao = sqlSession.getMapper(UserDao.class);//创建dao接口实现类使用了代理模式,不修改源码的基础上对已有方法增强
        //5.使用代理对象执行方法
        List<User> list = dao.findAll();
        for(User user:list){
            System.out.println(user);
        }
        //6.释放资源
        sqlSession.close();
        in.close();
    }
}

运行成果:
在这里插入图片描述
最后的包结构:
在这里插入图片描述
总结:
mybatis基于注解的入门案例也在上边掺杂了,就是把UserDao.xml移除掉,在dao接口的方法上使用@Select注解,并且指定SQL语句,同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口实现的全限定类名。
搭建环境时候需要注意:
1.mybatis中的mapper其实就是dao。
2.在idea中创建目录的时候需要注意(directory),他不同于包(package),目录想要和包一样的时候需要一级一级地创建的!
3.mybatis的映射文件位置必须和dao接口的包结构相同
4.映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
5.映射配置文件的操作设置(select),id属性的取值必须是dao接口的方法名

当我们在开发中遵从了第三、四、五点之后,我们在开发中就无须再写dao的实现类。

四、自定义一个简单的MyBatis框架

1.MyBatis在使用dao的方式实现增删改查的时候都做了什么?

		//1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        UserDao userDao = session.getMapper(UserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();

其实就做了两件事:

  • 1.1 创建代理对象
  • 1.2 在代理对象中调用selectList

2.实现的类都包括:

  • class Resources(测试类中的)
  • class SqlSessionFactoryBuilder(这个也存在于测试类中)
  • interface SqlSessionFactory(这个也是在测试类中的)
  • interface SqlSession(daoIml 中的)

最后形成的包结构:
在这里插入图片描述
此MyBatis的简单实现案例中包含了大量的优秀的设计模式思想,值得借鉴!

五、Mybatis的基本使用

写一个类似上边的案例

六、Mybatis的单表操作(CRUD)

1.保存单个用户操作

在UserDao.xml中新增:在这里插入图片描述
在userDao.java中新增:

 void saveUser(User user);

在Userdao.xml中新增

<insert id="saveUser" parameterType="com.zhou.domain.User">
        insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday});
    </insert>

在测试中新增:

		User user = new User();
        user.setUsername("mybatis_test");
        user.setAddress("杭州");
        user.setSex("男");
        user.setBirthday(new Date());

        //执行保存方法
        userDao.saveUser(user);//user对象必须传进来
        //提交事务
        sqlSession.commit();

2.更新一个用户操作

3.删除一个用户操作

4.根据id查询一个用户

5.根据名称模糊查询用户

6.查询总记录条数

所有方法的代码:
UserDao.java:

public interface UserDao {

    /**
     * 查询所有的方法
     */
    List<User> findAll();

    /**
     * 创建一个用于保存用户信息的方法
     */
    void saveUser(User user);

    /**
    * 创建一个方法用于更新用户操作
     */
    void updateUser(User user);

    /**
     * 创建一个方法用于删除操作
     */
    void deleteUser(Integer id);

    /**
     * 创建查询一个用户操作
     */
    User findById(Integer id);

    /**
     * 创建根据名字查询
     */
    List<User> findByName(String name);

    /**
     * 创建一个方法查询总记录条数
     */
    int findTotal();
}

UserDao.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.zhou.dao.UserDao">
    <select id="findAll" resultType="com.zhou.domain.User">
        select * from user;
    </select>

    <insert id="saveUser" parameterType="com.zhou.domain.User">
        <!-- 保存操作中,可以返回id的属性值,或者其他的属性值,下边的语句表示在执行插入操作之后返回一个int类型的id值
                其中第一个keyProperty表示的是id的属性值,第二个keyColumn表示的是插入到数据库的哪一列-->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday});
    </insert>

    <update id="updateUser" parameterType="com.zhou.domain.User">
        update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday}
        where id=#{id};
    </update>

    <!--注意这里的uid只是一个占位符,随便写个aa之类也是可以的-->
    <delete id="deleteUser" parameterType="Integer">
        delete from user where id=#{uid};
    </delete>

    <select id="findById" parameterType="int" resultType="com.zhou.domain.User">
        select * from user where id=#{uid};
    </select>

    <select id="findByName" parameterType="String" resultType="com.zhou.domain.User">
        <!-- select * from user where username like '%${value}%'; -->
        select * from user where username like #{username};
    </select>

    <select id="findTotal" resultType="int">
        select count(*) from user;
    </select>

</mapper>
</mapper>

测试类:

public class MyTest {

    private InputStream resourceAsStream;
    private SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private UserDao userDao;

    @Before //测试之前执行初始化工作
    public void init() throws IOException {
        resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
        factory = builder.build(resourceAsStream);
        sqlSession = factory.openSession();
        userDao = sqlSession.getMapper(UserDao.class);
    }

    @After  //测试完了之后提交事务,释放资源
    public void release() throws IOException {
        //提交事务
        sqlSession.commit();
        sqlSession.close();
        resourceAsStream.close();
    }

    /**
     * 测试查询所有操作
     */
    @Test
    public void test(){

        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }

    }

    /**
     * 测试保存一个用户的操作
     */
    @Test
    public void testSaveUser(){
        User user = new User();
        user.setUsername("奥术飞弹");
        user.setAddress("新疆");
        user.setSex("男");
        user.setBirthday(new Date());
        System.out.println("执行保存操作之前:"+user);
        //执行保存方法
        userDao.saveUser(user);//user对象必须传进来
        System.out.println("执行保存操作之后:"+user);
    }

    @Test
    public void updateUser(){
        User user = new User();
        user.setId(45);
        user.setUsername("不是人");
        user.setAddress("广州");
        user.setSex("女");
        user.setBirthday(new Date());
        userDao.updateUser(user);
    }

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

    @Test
    public void selectById(){
        User user = userDao.findById(48);
        System.out.println(user);
    }

    @Test
    public void findByName(){
        List<User> users = userDao.findByName("%人%");
        for(User user : users){
            System.out.println(user);
        }
    }

    @Test
    public void findTotal(){
        int total = userDao.findTotal();
        System.out.println(total);
    }


}

七、Mybatis的参数与返回值

1.MyBatis可以传进去的参数(parameterType)可以使基本的数据类型,也可以是pojo对象,类似于上边例子中的User,还可以是OGNL表达式,即对象图导航语言表达式,user.getUserName()在OGNL 中可以写成user.username,例如在添加一个根据对象查询的时候可以这样做:
在domain包中增加一个QueryVo:

public class QueryVo {

    private User user;

    public User getUser() {
        return user;
    }

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

在UserDao.xml中添加方法:

/**
     * 创建一个根据查询对象去查询的方法
     */
    List<User> findByVo(QueryVo vo);

在UserDao.xml添加查询语句(根据OGNL表达式查询):

<!-- 根据查询对象去查询,下边是用的就是OGNL表达式 -->
    <select id="findByVo" parameterType="com.zhou.domain.QueryVo" resultType="com.zhou.domain.User">
        select * from user where username like #{user.username};
    </select>

测试:

 @Test
    public void findByVo(){
        QueryVo vo = new QueryVo();
        User user = new User();
        user.setUsername("%人%");
        vo.setUser(user);
        List<User> users = userDao.findByVo(vo);
        for(User u:users)
            System.out.println(u);
    }

2.MyBatis中的结果类型参数可以是一个基本类型,也可以是一个pojo(实体类)对象,或者pojo 列表

八、Mybatis的dao编写

其实,所有的CUD(增删改)方法使用的都是update,而R(查询)使用的是selectList,最后执行的jdbc语句都是PrepareStatement中的execute()方法。execute()返回的都是boolean值,表示有没有结果集封装返回。
下边代码清晰表明了CUD的实质就是一个update:

 @Override
  public int insert(String statement) {
    return insert(statement, null);
  }

  @Override
  public int insert(String statement, Object parameter) {
    return update(statement, parameter);
  }

  @Override
  public int update(String statement) {
    return update(statement, null);
  }

  @Override
  public int update(String statement, Object parameter) {
    try {
      dirty = true;
      MappedStatement ms = configuration.getMappedStatement(statement);
     //在所有的cud操作中,executor.update方法是最重要的,他会到达CashingExecutor中的update方法
      return executor.update(ms, wrapCollection(parameter));
      
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error updating database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

  @Override
  public int delete(String statement) {
    return update(statement, null);
  }

  @Override
  public int delete(String statement, Object parameter) {
    return update(statement, parameter);
  }

CashingExecutor中的update方法:

@Override
  public int update(MappedStatement ms, Object parameterObject) throws SQLException {
    flushCacheIfRequired(ms);
    return delegate.update(ms, parameterObject);
  }

然后执行delegate.update(),此方法是Executor接口中的中的一个方法,由子类(抽象类)BaseExecutor实现:
Executor抽象类中的update()方法:

public interface Executor {

  ResultHandler NO_RESULT_HANDLER = null;

  int update(MappedStatement ms, Object parameter) throws SQLException;

抽象类BaseExecutor中的update方法:

@Override
  public int update(MappedStatement ms, Object parameter) throws SQLException {
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) {
      throw new ExecutorException("Executor was closed.");
    }
    clearLocalCache();
    return doUpdate(ms, parameter);
  }

此时返回的doUpdate()方法其实是个抽象方法:

protected abstract int doUpdate(MappedStatement ms, Object parameter)
      throws SQLException;

doUpdate()方法最后由继承抽象类BaseExecuto的 SimpleExecutor 来进行实现:

@Override
  public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
    Statement stmt = null;
    try {
      Configuration configuration = ms.getConfiguration();
      StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
      stmt = prepareStatement(handler, ms.getStatementLog());
      return handler.update(stmt);
    } finally {
      closeStatement(stmt);
    }
  }

这里返回的handler.update(stmt),其实是调用了接口StatementHandler中的抽象方法update(Statement statement):

int update(Statement statement)
      throws SQLException;

而这个方法由继承StatementHandler接口的实现类PreparedStatementHandler实现:

@Override
  public int update(Statement statement) throws SQLException {
    PreparedStatement ps = (PreparedStatement) statement;
    ps.execute();
    int rows = ps.getUpdateCount();
    Object parameterObject = boundSql.getParameterObject();
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
    return rows;
  }

到此,MyBatis调用的jdbc语句终于出现了,就是使用了PreparedStatement 的execute()方法来进行操作的。

而查询方法R,无论是带参数查询还是不带参数查询,执行的最后都是同一个方法,下边的代码为证:

@Override
  public <E> List<E> selectList(String statement) {
    return this.selectList(statement, null);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }

  @Override
  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

使用mybatis之所以不用编写dao的实现类,关键在于它使用了代理的方式,获取getMapper,而在使用getMapper的时候其实最后调用的也是selectList等方法,然后执行的也是上边的过程,都是一样的执行过程。

九、Mybatis的配置细节(几个标签的使用)

重点是properties以及package的使用:

<!-- mybatis 的主配置文件-->
<configuration>
    <!-- 配置properties
         可以在标签内部配置连接数据库的信息,也可以通过属性引用外部配置文件的信息
         resource属性:用于指定配置文件的位置,是按照路径的写法来写的,并且需要在类路径下
         url属性:是要求按照Url的写法来填写地址
                URL:Uniform Resource Locator 统一资源定位符,他是可以唯一表示一个资源的位置的
             他的写法:
                     http://localhost:8080/mybatisServer/demo1
                     协议     主机     端口      URI
             URI:Uniform Resource Identifier 统一资源定位标识符。他是应用中可以唯一定位一个资源的。
         -->
<!--    <properties resource="jdbcConfig.properties">-->
    <!-- 使用url定位的话需要写完整的协议等信息 -->
    <properties url="file:///E:/Code/day02_mybatis_2/src/main/resources/jdbcConfig.properties">
<!--        <property name="driver" value="com.mysql.jdbc.Driver"></property>-->
<!--        <property name="url" value="jdbc:mysql://localhost:3306/test_mybatis"></property>-->
<!--        <property name="username" value="root"></property>-->
<!--        <property name="password" value="root"></property>-->
    </properties>

    <!-- 使用typeAliases配置别名,他只能配置domain中类的别名 -->
    <typeAliases>
        <!-- typeAlias用于配置别名,type属性制定的是实体类的全限定名,alias属性指定别名,当制定了别名,就不再区分大小写了 -->
<!--        <typeAlias type="com.zhou.domain.User" alias="user"></typeAlias>-->
        <!--下边的这个用于指定配置别名的包,当置顶了之后,该报下的实体类都会被注册别名,并且类名就是别名,不区分大小写-->
        <package name="com.zhou.domain"/>
    </typeAliases>
    <!-- 配置环境-->
    <environments default="mysql">
        <!--配置mysql的环境,这里的id需要和上边的定义的默认值保持一致-->
        <environment id="mysql">
            <!-- 配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池)-->
            <dataSource type="POOLED">
                <!-- 配置数据库的四个基本信息,驱动类型,url,username,password-->
                <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>
        </environment>
    </environments>
    <!-- 指定映射文件的配置,映射配置文件指的是每个dao独立的配置文件 com/xxx/dao/UserDao.xml
        如果使用注解的方式来配置的话,此处应该使用class属性指定北朱解的dao的全限定名 com.xxx.dao.UserDao-->
    <mappers>
<!--        <mapper resource="com/zhou/dao/UserDao.xml"/>-->
        <!-- package标签适用于指定dao接口所在包,当指定了之后就不需要写mapper以及resource或者class -->
        <package name="com.zhou.dao"></package>
    </mappers>
</configuration>

十、Mybatis的深入与多表操作

与多表查询合在一起来写了。

十一、Mybatis的连接池

我们在实际开发中都会使用到连接池,因为它可以减少我们获取连接的时间(用到的是一种队列数据结构的思想,即先进先出)。
mybatis中的连接池提供了三种方式的配置:type属性就是采用何种连接池的方式,type的取值包括:POOLED:采用传统的javax.sql.DataSource规范中的连接池
UNPOOLED:采用传统的获取连接的方式,虽然也实现了javax.sql.DataSource接口,但是并没有使用池
JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能获得的是不一样的。注意不是web或者war工程是不能使用的。而Tomcat服务器使用的是dbcp连接池。

十二、Mybatis的事务控制以及设计方法

关于事务,面试问题一般会涉及:1.什么识事务,2.事务的四大特性,3.不考虑隔离会产生的3个问题,4.解决方法:四种隔离的级别

十三、Mybatis的多表查询(一对多,多对多)

1.使用mybatis的时候常用的sql标签:

:抽取重复的sql语句
:使用标签内得sql语句
:条件判断语句
:就是where的查询,可以包裹
:循环遍历语句
标签使用实例:

<?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.zhou.dao.UserDao">

    <resultMap id="userMap" type="com.zhou.domain.User">
        <result property="id" column="id"></result>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
    </resultMap>

    <!-- 可以抽取重复的sql内容 -->
    <sql id="findUser">
        select * from user
    </sql>

    <select id="findAll" resultType="com.zhou.domain.User">
        <include refid="findUser"></include>
    </select>
    <!-- 使用where标签可以不写1=1永远为真的语句,是语句更加简洁,清晰 -->
    <select id="findByUserCondition" resultMap="userMap" parameterType="user">
        select * from user
        <where>
            <if test="username != null">
                and username like #{username}
            </if>
            <if test="sex != null">
                and sex = #{sex}
            </if>
        </where>

    </select>

    <!-- 根据query中的id实现查询用户列表,子查询 -->
    <select id="findUserInIds" resultMap="userMap" parameterType="queryVo">
        <include refid="findUser"></include>
        <if test="ids != null and ids.size()>0">
            <foreach collection="ids" open="where id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </if>
    </select>

</mapper>

2.一对一,一对多等关系的的概念阐述

用户与订单的关系(一对多,多对一):
一对多:比如一个用户可以对应多个订单
多对一:比如多个订单可以对应一个用户

人和身份证(一对一):一个人只有一个身份证号,一个身份证号只能对应一个人

大学老师和学生的关系(多对多):一个老师可以教多个学生,一个学生也可以上多个老师的课程,并允许交叉

但是也有特殊的,比如说一个订单对应的只能是一个用户,所以上边分析的一对多其实很多时候就是一对一的一种特例,mybatis 就是把一对多或者多对一看成了一对一的。

3.建立一对多的案例

步骤:
1.建立一个用户表和一个账户表,一个用户可以有多个账户,一个账户只能属于一个用户(多个账户可能同属于一个用户),所以在账户表(多的一方)添加外键。
2.创建两个实体类,同时创建两个查询的xml
3.实现的功能:查询一个用户的时候可以查询到它对应的所有的账户信息,查询一个账户的时候,可以查询到它对应的用户的信息。

4.用户与角色的关系
用户可以有多个角色。一个角色可以赋予多个用户。使用中间表表示多对多的关系。

十四、Mybatis的缓存以及注解开发

缓存就是存在于内存里的临时数据。使用缓存的原因:减少和数据库交互的次数,提高效率。
经常查询并且不经常改变的数据可以使用缓存。数据正与否对最终的结果影响不大的也可以使用缓存。
经常改变的数据,数据的正确与否对最终的结果影响很大的情况下都不能使用缓存。例如商品库存,银行汇率,股市牌价
Mybatis的缓存:
一级缓存:指的是MyBatis中的SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中,该区域的结构是一个Map,当我们再次发起查询同样的数据的时候,mybatis回西安区sqlsession中去查询是否有,有的话直接拿出来使用。当SqlSession对象小时的时候,以及缓存也会跟着消失。
二级缓存:指的是MyBatis中的SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建。
二级缓存使用步骤:

  1. 让mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
  2. 让当前配置文件支持二级缓存(在UserDao.xml中配置)
  3. 让当前的操作支持二级缓存(在select标签中配置)

十五、Mybatis中的加载时机(查询的时机)

1.延迟加载:在真正使用数据的时候才发起查询,不用的时候不查询,按需查询(懒加载)。
例如在查询用户的时候,用户下的账户信息是什么时候使用,什么时候查询出来?(可能一个用户有100多个账户,立即加载出来得时候会极大地浪费内存空间)
2.立即加载:不管用不用,只要发起查询就马上发起查询。例如,查询一个账户对应的用户信息。
一般来说,一对多,多对多中都是用延迟加载;而多对一,或者一对一中就使用立即加载。

十六、Mybatis的注解开发以及单表CRUD/多表的查询

Mybatis中一旦使用了注解开发就不能再使用xml文件的了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值