MyBatis学习笔记

MyBatis学习笔记

1、MyBatis相关概念:

基本概念:

前身:MyBatis 本是apache的一个开源项目iBatis 。未来我们编写代码的时候,导入包的时候可以看到很多ibatis的包,就是我们的MyBatis。

MyBatis源码:需要在 Github 上下载!

官网地址:https://mybatis.org/mybatis-3/

什么是“持久化” ?

  • 持久(Persistence),即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的数据存储在关系型的数据库中,当然也可以存储在磁盘文件中、XML数据文件中等等。

什么是 “持久层” ?

  • 持久层(Persistence Layer),即专注于实现数据持久化应用领域的某个特定系统的一个逻辑层面,将数据使用者和数据实体相关联

MyBatis 的特性:

  • MyBatis 是一款优秀的持久层框架
  • 它支持定制化 SQL、存储过程以及高级映射。
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

问题:MyBatis 是如何读取配置文件进行加载的?运行原理是什么

个人见解

  • 我们在MyBatis中经常需要把一条记录抽象为一个具体的对象
  • 光通过在MyBatis上配置就可以获得数据库的查询结果,其实就跟我们写的JDBC工具类一样,只不过它更为高级和简化一些。
  • 如果MyBatis只到这种程度,估计还算不上特别大的功能,这些抽象到最后可能会被进一步封装,最后能让我们实现所谓的ORM
  • ORM:Object-Relationl Mapping,它的作用是在关系型数据库和对象之间作一个映射,这样,我们在具体的操作数据库的时候,就不需要再去和复杂的SQL语句打交道,只要像平时操作对象一样操作它就可以了(不再需要编写SQL语句了,直接用这个对象即可)。
2、MyBatis 使用案例:

实验过程:

```mermaid

st=>start: 搭建环境
op=>operation: 导入包
op2=>operation: 写代码
e=>end: 测试

st->op->op2->e->
```

1、准备一个数据库:

1CREATE DATABASE `mybatis`;

2USE `mybatis`;


3CREATE TABLE `user`(
    `id` INT(20) NOT NULL,
    `name` VARCHAR(30) DEFAULT NULL,
    `pwd` VARCHAR(30) DEFAULT NULL,
     PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`)
VALUES (1,'周丹','123456'),(2,'周颖','zxcvbn'),(3,'姜嘉航','123456');

2、准备相关jar包的依赖:(在Maven 仓库中查询的结果)

1)先创建一个空的Maven项目(模板:无

2)在pom.xml中的相应位置添加依赖:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

3、编写配置文件:resources/mybatis-config.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>

    <settings>
        <setting name="logImpl" value="NO_LOGGING"/>
    </settings>

    <environments default="development">
      <!--这里只是一个环境,还可以配置多个环境-->
        <environment id="development"> 
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?
useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
  	<!--mappers 中配置的是需要解析.xml文件-->
 	  <mappers>
        
    </mappers>
</configuration>

4、编写一个工具类来操作数据库:(目的是为了获取SqlSession对象)

在 main/java 下新建一个包:edu.nwu.utils,创建 MybatisUtils类:

package edu.nwu.utils;

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 javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 工厂模式:
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }catch (IOException e){
            e.printStackTrace();
        }


    }

    // 获取sqlSession的连接:
    public static SqlSession getSession(){

        return sqlSessionFactory.openSession();

    }
}

5、配置了一个实体类,引入了Lombok

LomBok概念:

  • 以前的Java项目中,充斥着太多不友好的代码:
  • POJO的getter/setter/toString;异常处理;I/O流的关闭操作等等,这些样板代码既没有技术含量,又影响着代码的美观
  • Lombok就是为了解决这些问题应运而生,使用注解来代替这些重复的代码,简化开发流程。

LomBok相关依赖:

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
        <scope>provided</scope>
    </dependency>

在 main/java 下创建一个包:edu.nwu.pojo 创建文件类:User

package edu.nwu.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

6、持久层的操作接口:(MyBatis的规则)

在 main/java 下 创建:edu.nwu.mapper包,创建 UserMapper映射类:

package edu.nwu.mapper;

import com.kuang.pojo.User;

import java.util.List;

// 操作用户的接口类(这里可以写多个实现方法)
public interface UserMapper {

    List<User> getUserList();
    
    User selectById(int id);

}

7、本来我们需要编写接口的实现类,使用了MyBatis之后,我们可以专注写SQL来配置文件。

在resources 目录下:创建于刚才映射接口同级的包:edu.nwu.mapper,创建UserMapper.xml(文件名也是同步映射过来的,知不是转为了.xml文件)

这样做的好处:

  • 当程序运行起来以后,我们依旧可以动态的修改代码
  • 假设这个.java文件是放到Web应用程序下的,每一次启动服务器后,这些代码就被编译成.class 文件,用于执行逻辑。如果代码发生的话,想要生效必须重新编译生成新的.class文件。
  • 但在Mybatis中,我们由于这些SQL执行逻辑都写在配置文件中,而不是代码中,所以我们可以动态地修改代码,这起到了程序解耦的作用。

与相关接口对应的.xml配置文件的写法:

  • namespace 绑定对应的接口,
  • 标签和操作相对应:查询 => select , 添加 => insert , 更新 => update ,删除 => delete
  • 具体操作(CRUD)中的 id 为接口中的方法名
<?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="edu.nwu.mapper.UserMapper">
  	<!-- 原来我们都是编写具体的执行SQL,这里可以引入一些参数写法都是:#{数据库/对象字段名} -->
    <select id="getUserList" resultType="edu.nwu.pojo.User">
      select * from user;
    </select>

    <select id="selectById" resultType="edu.nwu.pojo.User">
      select * from user where id = #{id};
    </select>
      
</mapper>

8、这个配置文件一定要注册到Mybatis的配置文件(resources/mybatis-config.xml)中(重要)

<mapper resource="edu/nwu/mapper/UserMapper.xml"/>

9、编写测试类运行:

在test/java 下创建 Test 测试类:

import edu.nwu.mapper.UserMapper;
import edu.nwu.mapper.UserMapperX;
import edu.nwu.pojo.User;
import edu.nwu.pojo.UserX;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

public class Test {

    static  Logger logger = Logger.getLogger(Test.class);

    public static void main(String[] args) {
				selectById();
        System.out.println("=========");
        selectAll();
    }

    public static void selectById(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);

        User user = mapper.selectById(1);
        System.out.println(user);
    }

  	public static void selectAll(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}
------------
结果:
User(id=1, name=周丹, pwd=123456)
=========
User(id=1, name=周丹, pwd=123456)
User(id=2, name=周颖, pwd=1asdfasd)
User(id=3, name=小波, pwd=1ssssfasd)
3、CRUD 增删改查:

固话的操作流程:

1、编写(新/旧)接口中的方法;

2、编写接口对应的SQL配置文件(一定要确保配置文件的SQL的正确性)

3、编写测试类进行测试:

需要注意的点:

1、多个参数一定要增加 @Param 注解

2、增删改一定要增加事务提交

3、.xml中的增删改,标签一定要写对应,传入的参数类型必须要写。*

4、在*.xml中的, 标签一定也要写对应,传出参数类型必须要写。

5、增删改不用写返回值,查询必须写返回值,注意:是集合、泛型中的内容(具体的某个对象的类型

代码案例:

1、通过id 查询用户 User selectById(int id);

2、通过用户名和密码查询用户 User selectByUsernamePwd(String username, String pwd);

3、新增一个用户 int addUser(User user);

4、修改用户信息 int updateUser(User user);

5、删除一个用户 int deleteUserByID(int id);

  • 更改接口类:
package edu.nwu.mapper;

import edu.nwu.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
// 操作用户的接口类
public interface UserMapper {
    List<User> getUserList();

    User selectById(int id);

    User selectByUsernamePwd(@Param("username") String username, @Param("pwd") String pwd);

    // 添加一个用户的方法:
    int addUser(User user);

    // 删除一个用户的方法:
    int deleteUser(User user);

    // 更新一个用户记录的方法:(这个返回值的意义是:有几条记录参与修改成功)
    int updateUser(User user);

}
  • 更改接口类所对应的.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="edu.nwu.mapper.UserMapper">
    <select id="getUserList" resultType="edu.nwu.pojo.User">
      select * from user;
    </select>

    <select id="selectById" resultType="edu.nwu.pojo.User">
      select * from user where id = #{id};
    </select>

    <select id="selectByUsernamePwd" resultType="edu.nwu.pojo.User">
      select * from user where name = #{username} and pwd= #{pwd};
    </select>

    <insert id="addUser" parameterType="edu.nwu.pojo.User">
        insert into `user`(`id`,`name`,`pwd`) values (#{id},#{name},#{pwd});
    </insert>

    <delete id="deleteUser" parameterType="edu.nwu.pojo.User">
        delete from `user` where id=#{id} and name=#{name} and pwd = #{pwd} ;
    </delete>

    <update id="updateUser" parameterType="edu.nwu.pojo.User">
        update `user` set name=#{name},pwd=#{pwd} where id=#{id};
    </update>


</mapper>
  • 注册到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">
<configuration>

    <settings>
        <setting name="logImpl" value="NO_LOGGING"/>
    </settings>

    <environments default="development">
        <!--这里只是一个环境,还可以配置多个环境-->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?
useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="edu/nwu/mapper/UserMapper.xml"/>
        <mapper 
    </mappers>
</configuration>
  • 编写测试类:
import edu.nwu.mapper.UserMapper;
import edu.nwu.mapper.UserMapperX;
import edu.nwu.pojo.User;
import edu.nwu.pojo.UserX;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

import java.util.List;

public class Test {

    static  Logger logger = Logger.getLogger(Test.class);

    public static void main(String[] args) {

        selectById();
        System.out.println("=========");
        selectAll();
//        insert();
//        delete();
//        update();
    }

    public static void select(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);

        User user1 = mapper.selectByUsernamePwd("周丹","123456");
        System.out.println(user1);

    }

    public static void selectById(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);

        User user = mapper.selectById(1);
        System.out.println(user);
    }

    public static void selectAll(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }

    public static void update(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);
        int i = mapper.updateUser(new User(10, "超级可爱的佳露宝", "xuankulanzuan9"));
        System.out.println(i);
        session.commit();
    }

    public static void insert(){
        // 1、 获取SqlSession, 执行sql使用的
        SqlSession session = MybatisUtils.getSession();
        // 2、通过 session.getMapper(Class ) 获得接口
        UserMapper mapper = session.getMapper(UserMapper.class);
        int x = mapper.addUser(new User(5, "佳露宝", "123456"));
        System.out.println(x);
        session.commit();
    }



    public static void delete(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int x =  mapper.deleteUser(new User(5, "佳露宝", "123456"));
        System.out.println(x);
        session.commit();

    }
}

注意:

  • 增删改方法执行完对应的返回值是int类型的数据,其代表了到底有多少行记录生效了。
  • 一般返回1代表1条记录生效。
  • 返回0代表0行记录生效,也就是失败!
4、Mybatis 配置文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KKdUe27Z-1582305117228)(/Users/zhengjiaxiang/Desktop/MyBatis/MyBatis.assets/image-20200219144228349.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oY1wDC9l-1582305194393)(/Users/zhengjiaxiang/Desktop/MyBatis/MyBatis.assets/image-20200219144228349.png)]
注意:

  • 这些配置项是有顺序的(顺序如图所示)
  • 圈红部分为常用重要的配置项

配置db.properties 让配置文件读取数据库的相关信息:

1、编写配置文件,文件位置为:resources/db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456

2、在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">
<configuration>

    <!--xml 中元素的标签上下位置是有要求的-->
    <!-- 将配置文件改为properties -->
    <properties resource="db.properties"/>

    <!-- 一个environments 标签元素可以有多套配置 -->
    <environments default="development">
        <!-- 里面的每一个environment代表一个具体的环境 -->
        <environment id="development">
            <!--transactionManager 事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- dataSource 数据源配置 -->
            <dataSource type="POOLED">
                <!-- 连接数据库的配置i-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="edu/nwu/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

通过Settings 设置普通日志。

目的:

  • 查看系统的启动过程(拍错)
  • 可以看到拼接SQL的过程,以此来查看自己的SQL是否转换出错等等

1、更改Mybatis主配置文件:

<settings>
        <!--<setting name="logImpl" value="NO_LOGGING"/>  这个是关闭日志的选项-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

2、输出结果查看:

/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60686:/Applications/IntelliJ IDEA.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/lib/tools.jar:/Users/zhengjiaxiang/IdeaProjects/Mybatis-Test/target/test-classes:/Users/zhengjiaxiang/IdeaProjects/Mybatis-Test/target/classes:/Users/zhengjiaxiang/Library/maven/maven-repo/org/mybatis/mybatis/3.5.4/mybatis-3.5.4.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/mysql/mysql-connector-java/5.1.47/mysql-connector-java-5.1.47.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/org/projectlombok/lombok/1.18.8/lombok-1.18.8.jar:/Users/zhengjiaxiang/Library/maven/maven-repo/log4j/log4j/1.2.17/log4j-1.2.17.jar Test
[DEBUG] 2020-02-19 22:07:43,305 method:org.apache.ibatis.logging.LogFactory.setImplementation(LogFactory.java:105)
Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
Opening JDBC Connection
Created connection 1188753216.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@46daef40]
==>  Preparing: select * from user where id = ?; 
==> Parameters: 1(Integer)
<==    Columns: id, name, pwd
<==        Row: 1, 周丹, 123456
<==      Total: 1
User(id=1, name=周丹, pwd=123456)
=========
Opening JDBC Connection
Created connection 682376643.
Setting autocommit to false on JDBC Connection [com.mysql.jdbc.JDBC4Connection@28ac3dc3]
==>  Preparing: select * from user; 
==> Parameters: 
<==    Columns: id, name, pwd
<==        Row: 1, 周丹, 123456
<==        Row: 2, 周颖, 1asdfasd
<==        Row: 3, 小波, 1ssssfasd
<==        Row: 4, 郑嘉祥, 123456
<==        Row: 10, 超级可爱的佳露宝, xuankulanzuan9
<==      Total: 5
User(id=1, name=周丹, pwd=123456)
User(id=2, name=周颖, pwd=1asdfasd)
User(id=3, name=小波, pwd=1ssssfasd)
User(id=4, name=郑嘉祥, pwd=123456)
User(id=10, name=超级可爱的佳露宝, pwd=xuankulanzuan9)

通过Settings 设置log4j日志

Log4j:在工作中用的更多,它可以按照级别配置日志的输出与保存等等,功能更为强大!

1、导入相关的依赖:

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

2、在resources目下下,创建:log4j.properties文件:

### 设置###
log4j.rootLogger = debug,stdout,D,E


### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=E://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=E://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =./log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout

3、在Mybatis主配置文件中修改日志选项:

<settings>
        <!--<setting name="logImpl" value="NO_LOGGING"/>-->
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

4、会自动生成对应的log日志目录(根据log4j.properties所得)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0HkyHtnN-1582305117229)(MyBatis学习笔记.assets/Xnip2020-02-19_22-18-05.jpg)]

5、还能在函数中具体使用它们来代替print

import org.apache.log4j.Logger;

public class Test1 {
    // 注意导入包的问题  org.apache.log4j.Logger
    static Logger logger = Logger.getLogger(Test1.class);

    public static void main(String[] args) {

        SqlSession session = MyBatisUtils.getSession();
        RMapper mapper = session.getMapper(RMapper.class);

        System.out.println("1231321222222");// 普通的输出

        // 通过log4j 可以将日志实现细粒度的控制;
        logger.error("1231321222222"); // 错误信息
        logger.info("1231321222222"); // 提示信息
        logger.debug("1231321222222");

    }
}

配置类型别名,简化开发

注意:

  • 起别名也是在mybayis的配置文件中去配的,在其中去声明

配置文件:

<!--包的别名配置-->
    <typeAliases>
        <!-- 给包下所有类起别名 -->
        <package name="edu.nwu.pojo"/>
        <!-- 给一个类起别名 alias是自己起的别名-->
        <!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
    </typeAliases>

接口所对应的配置文件:(注意上下两者的区别,其了别名以后就可以直接使用User了)

<select id="getUserList" resultType="User">
  select * from user;
</select>

<select id="selectById" resultType="edu.nwu.pojo.User">
  select * from user where id = #{id};
</select>

配置 mapper 映射器,来扫描一个包下的内容:(常用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XX63gv4w-1582305117229)(MyBatis学习笔记.assets/image-20200219145755295.png)]

特点:这样的话,即使创建再多的接口,我们也不用没一个都注册到Mybatis主配置文件中去了,只需要把路径对应写好就OK

1、设置主配置文件:

<mappers>
        <!--<mapper resource="edu/nwu/mapper/UserMapper.xml"/>-->
        <!--<mapper resource="edu/nwu/mapper/UserMapperX.xml"/>-->
        <package name="edu.nwu.mapper"/>
</mappers>

2、项目文件结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m5d55LZQ-1582305117229)(MyBatis学习笔记.assets/Xnip2020-02-19_22-33-59.jpg)]

5、ResultMap

问题:假如我们定义的类的属性名和数据库字段中的名字不一致!

问题呈现:

下面使我们定义的用户类:

package edu.nwu.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserX {
    private int id;
    private String name;
    private String password;
}

数据相关字段如下:

mysql> desc user;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(20)     | NO   | PRI | NULL    |       |
| name  | varchar(30) | YES  |     | NULL    |       |
| pwd   | varchar(30) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.00 sec)

我们发现:其password和pwd不对应。

注意:如果直接在原类中修改字段属性,可能会造成连锁的反应,不推荐这修改。

接口:

package edu.nwu.mapper;

import edu.nwu.pojo.UserX;

public interface UserMapperX {
    UserX selectById(int id);
}

其接口对应的配置文件:

<?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="edu.nwu.mapper.UserMapperX">
    <select id="selectById" resultType="UserX">
      select * from user where id = #{id};
    </select>
</mapper>

这样使用的时候,会造成一种情况:(由于字段不对应造成null值)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8vVp0tA-1582305117230)(MyBatis学习笔记.assets/Xnip2020-02-19_22-43-36.jpg)]

方法:通过Mapper映射!

1、在接口对应的配置文件中:resources/UserMapperX.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="edu.nwu.mapper.UserMapperX">

    <resultMap id="UserMap" type="edu.nwu.pojo.UserX">
        <!--这里只需要对不对应的字段进行映射处理即可!-->
        <result column="pwd" property="password"/>
    </resultMap>

    <select id="selectById" resultMap="UserMap">
    <!--<select id="selectById" resultType="UserX">&#45;&#45; -->
      select * from user where id = #{id};
    </select>
</mapper>

执行结果:(null值已经正常!)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMRG4Gvz-1582305117230)(MyBatis学习笔记.assets/image-20200219224800726.png)]

6、分页(一定要会)

为什么要分页?

目的:提高服务器性能,按照一小部分一小部分来处理我们的数据。

Limit :(语法)

select * from user limit startIndex,Pagesize

在接口中添加函数:(特别注意使用的参数传递方法!)

注意:

  • 这里我们使用的是Map来作为SQL配置文件解析的参数,当我们的实体类或者数据库中的表的字段过多时,我们就应当考虑Map了!
  • 它算是一种万能的参数传递方法

Mybatis的Sql方法中能够传递参数的方法:

  • Map传递参数,直接在sql中取出即可!
  • 对象传递传递参数,直接在sql中取出对象属性即可。(但得构建一个完整的对象)
  • 只有一个基本类型参数的情况下,可以直接在sql中取到。
  • 多个参数用Map,或者注解
// 带分页的操作
// 参数如果超过两个,可以使用map来进行传递指
// key value
List<User> selectUserByLimit(Map<String,Integer> map);

配置接口对应的文件:

 <!-- 非基本类型之外的数据类型,如:List、Map等类型需要显示的定义 -->
    <select id="selectUserByLimit" parameterType="map" resultType="User">
        select * from user limit #{startIndex},#{pageSize}
    </select>

注意:测试类 map 中的key,必须要和 sql 中接收的参数一致。

// 测试分页!
public static void limitTest() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);

        int currentPage = 2; //第几页
        int pageSize = 3; //每页显示几个

        HashMap<String, Integer> map = new HashMap<String, Integer>();
        // 分页     第几页    每页显示几个
        map.put("startIndex", (currentPage - 1) * pageSize);
        map.put("pageSize", pageSize);

        List<User> users = mapper.selectUserByLimit(map);
        for (User user : users) {
            logger.debug(user);
        }
    }

这个只是SQL层面的分层,我们还有在Java层面实现的分层:RowBounds

RowBounds 分页(拓展了解)

扩展 : 分页插件 PageHelper

地址:https://pagehelper.github.io/ 也可通过插件实现分页!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P7RvePpl-1582305117231)(MyBatis学习笔记.assets/image-20200219164903480.png)]

7、模糊查询:

1、在接口中创建方法:

List<User> getUserLike(String value);

2、在xml文件中添加实现:

<select id="getUserLike" resultType="User">
        select * from user where name like #{value};
</select>

3、注册到主配置文件中(我们已经设置了包扫描,所以不用担心这个)

4、编写测试类:

public static void getUserLike(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> userLike = mapper.getUserLike("郑%");
        for (User user : userLike) {
            System.out.println(user);
        }
    }

5、这样写不够安全,用户传进来的数值里存在特殊字符,容易造成安全问题,所以也可以把这种通配的符号写在配置文件中:

<select id="getUserLike" resultType="User">
  select * from user where name like "%"#{value}"%";
</select>
8、生命周期和作用域:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jHfJ8M9W-1582305117231)(MyBatis学习笔记.assets/1569660357745.png)]

生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题

官方参考文档:作用域(Scope)和生命周期中有更为详细的解释!

SqlSessionFactoryBuilder:

  • 一旦创建了 SqlSessionFactory,就不再需要它了
  • 局部变量

SqlSessionFactory:

  • 说白了就是可以想象为 :数据库连接池
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 连接到连接池的一个请求!
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wWIho2pF-1582305117231)(MyBatis学习笔记.assets/1569660737088.png)]

这里面的每一个Mapper,就代表一个具体的业务!

9、工厂模式

参考:狂神的Java视频所述

10. Mybatis 进阶(一对多、多对一)

概念:

在多对一的案例中:多个学生对应一个老师,此时的个体是老师(即:老师类中不会存在包含其他类对象属性),学生和老师之间的关系是:“关联”,即:每个学生都可以关联一个老师。(关联代指一个对象

在一对多的案例中:一个老师可以对应多个学生,此时的个体是学生(即:学生类中不会存在包含其他的类对象属性),老师和学生之间的关系时:”包含“,即:每一个老师都可能包含一个或多个学生对象。(集合代指多个对象

注意:其实没有所谓的多对多,其实只有一对多或者多对一,多对多用的也是这两个理念。

多对一:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J7aYmfR4-1582305117232)(MyBatis学习笔记.assets/1569909163944.png)]

  • 多个学生 对应 一个老师
  • 对于学生这边而言与老师的关系时:[ 关联] ,多个学生关联一个老师 【多对一
  • 对于老师而言与学生的关系是:[集合] , 一个老师有很多学生 【一对多

案例演示:

准备:数据库:

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师'); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8


INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1'); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');

0、创建Mybatis项目(或者创建Maven项目导入Mybatis模块)

项目目录如下结构所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-50rRZveY-1582305117232)(MyBatis学习笔记.assets/image-20200221204611268.png)]

1、编写pom.xml文件:添加依赖

<?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">
    <parent>
        <artifactId>Mybatis-Test</artifactId>
        <groupId>edu.nwu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-02</artifactId>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId> org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

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

    </dependencies>
</project>

2、编写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">
<configuration>

    <!--xml 中元素的标签上下位置是有要求的-->
    <!-- 将配置文件改为properties -->
    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <!--<setting name="logImpl" value="LOG4J"/>-->
    </settings>

    <!--包的别名配置-->
    <typeAliases>
        <!-- 给包下所有类起别名 -->
        <package name="edu.nwu.pojo"/>
        <!-- 给一个类起别名 alias是自己起的别名-->
        <!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
    </typeAliases>

    <!--<environments default="development">-->
        <!--&lt;!&ndash;这里只是一个环境,还可以配置多个环境&ndash;&gt;-->
        <!--<environment id="development">-->
            <!--<transactionManager type="JDBC"/>-->
            <!--<dataSource type="POOLED">-->
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <!--<property name="url" value="jdbc:mysql://localhost:3306/mybatis?-->
<!--useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>-->
                <!--<property name="username" value="root"/>-->
                <!--<property name="password" value="123456"/>-->
            <!--</dataSource>-->
        <!--</environment>-->
    <!--</environments>-->
    <!-- 一个environments 标签元素可以有多套配置 -->
    <environments default="development">
        <!-- 里面的每一个environment代表一个具体的环境 -->
        <environment id="development">
            <!--transactionManager 事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- dataSource 数据源配置 -->
            <dataSource type="POOLED">
                <!-- 连接数据库的配置i-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="edu.nwu.dao"/>
    </mappers>
</configuration>

其中数据库的相关信息都在db.properties下:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456

3、编写工具类:(注意这里的数据库事务自动提交与否,方法重载)

package edu.nwu.utils;

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 java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 工厂模式:
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }catch (IOException e){
            e.printStackTrace();
        }


    }

    // 获取sqlSession的连接:所有的增删改都需要我们手动提交事务
    public static SqlSession getSession(){

        return sqlSessionFactory.openSession();

    }


    // 如果你增加了true这个参数,它就会自动提交事务。(不需要session.commit()了)
    public static SqlSession getSession(boolean flag){
        return sqlSessionFactory.openSession(flag);

    }
}

4、编写pojo下的实体类:要在Student中体现多对一

package edu.nwu.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;

    // 学生需要管理一个老师

    private Teacher teacher;
}
package edu.nwu.pojo;

import lombok.Data;

import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;

}

5、编写接口类:StudentMapper

package edu.nwu.dao;

import edu.nwu.pojo.Student;


import java.util.List;

public interface StudentMapper {

    List<Student> getStudents();

    // 连接查询获得学生对象
    Student getStudentById(int id);

    // 子查询获得学生对象
    Student getStudentById2(int id);

}

6、编写resources包下对应的配置文件:StudentMapper.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="edu.nwu.dao.StudentMapper">

    <select id="getStudents" resultType="Student">
        select * from student;
    </select>
		
  	<!--连接查询的写法:-->
    <select id="getStudentById" resultMap="StudentTeacher">
        select s.name sname,s.id sid,t.name tname,t.id tid
        from student s,teacher t
        where s.tid = t.id and s.id = #{id}
    </select>

    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
      	<!--多对一使用的是:association关联,相当于设置表中这个属性关联的是一个对象-->
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>

    </resultMap>

  	<!--子查询的写法:-->
    <select id="getStudentById2" resultMap="StudentTeacher2">
        select * from student where id = #{id}
    </select>

    <resultMap id="StudentTeacher2" type="Student">
      	<!--多对一使用的是:association关联,相当于设置表中这个属性关联的是一个对象-->
        <association property="teacher" javaType="Teacher" column="tid" select="selectTeacher"/>
    </resultMap>
		<!--子查询语句:-->
    <select id="selectTeacher" resultType="Teacher">
        select * from teacher where id= #{tid};
    </select>
</mapper>

7、编写测试代码进行测试:

联表查询:

@org.junit.Test
    public void selectById(){
        SqlSession session = MybatisUtils.getSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        Student student = mapper.getStudentById(1);
        System.out.println(student);
        session.close();

    }

执行结果:

==>  Preparing: select s.name sname,s.id sid,t.name tname,t.id tid from student s,teacher t where s.tid = t.id and s.id = ? 
==> Parameters: 1(Integer)
<==    Columns: sname, sid, tname, tid
<==        Row: 小明, 1, 秦老师, 1
<==      Total: 1
Student(id=1, name=小明, teacher=Teacher(id=1, name=秦老师))

嵌套查询:

@org.junit.Test
    public void test3(){
        SqlSession session = MybatisUtils.getSession();
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        Student student = mapper.getStudentById2(2);
        System.out.println(student);
        session.close();
    }

查询结果:

==>  Preparing: select * from student where id = ? 
==> Parameters: 2(Integer)
<==    Columns: id, name, tid
<==        Row: 2, 小红, 1
====>  Preparing: select * from teacher where id= ?; 
====> Parameters: 1(Integer)
<====    Columns: id, name
<====        Row: 1, 秦老师
<====      Total: 1
<==      Total: 1
Student(id=2, name=小红, teacher=Teacher(id=1, name=秦老师))

区分联表查询和子查询

  • 联表查询:一条联表查询语句能够直接返回所得的数据,所以我们要做的工作是要把结果表中的每一条数据对应到类中去。此时Map的作用是将表中的结果映射到对象中去。
  • 子查询:一条子查询语句要分两个阶段实行,第一阶段是查找学生信息,第二阶段才是通过学生表中对应的tid来查询teacher表中的对应记录。此时Map的作用是:需要再执行一条select语句来获取对应的结果才能和类对应匹配。
  • 小结:其实联表查询更容易使用,但子查询更好理解一些。

一对多

概念:形如一个老师拥有多个学生!对于老师这个个体而言,就是一对多的关系!

0、创建Mybatis项目(或者创建Maven项目导入Mybatis模块)

项目目录如下结构所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yfKjB6wr-1582305117232)(MyBatis学习笔记.assets/image-20200221212230517.png)]

1、编写pom.xml配置文件:

<?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">
    <parent>
        <artifactId>Mybatis-Test</artifactId>
        <groupId>edu.nwu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>Mybatis-01</artifactId>

    <dependencies>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId> org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

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

    </dependencies>
</project>

2、编写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">
<configuration>

    <!--xml 中元素的标签上下位置是有要求的-->
    <!-- 将配置文件改为properties -->
    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="NO_LOGGING"/>
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <!--<setting name="logImpl" value="LOG4J"/>-->
    </settings>

    <!--包的别名配置-->
    <typeAliases>
        <!-- 给包下所有类起别名 -->
        <package name="edu.nwu.pojo"/>
        <!-- 给一个类起别名 alias是自己起的别名-->
        <!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
    </typeAliases>

    <!--<environments default="development">-->
        <!--&lt;!&ndash;这里只是一个环境,还可以配置多个环境&ndash;&gt;-->
        <!--<environment id="development">-->
            <!--<transactionManager type="JDBC"/>-->
            <!--<dataSource type="POOLED">-->
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <!--<property name="url" value="jdbc:mysql://localhost:3306/mybatis?-->
<!--useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>-->
                <!--<property name="username" value="root"/>-->
                <!--<property name="password" value="123456"/>-->
            <!--</dataSource>-->
        <!--</environment>-->
    <!--</environments>-->
    <!-- 一个environments 标签元素可以有多套配置 -->
    <environments default="development">
        <!-- 里面的每一个environment代表一个具体的环境 -->
        <environment id="development">
            <!--transactionManager 事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- dataSource 数据源配置 -->
            <dataSource type="POOLED">
                <!-- 连接数据库的配置i-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <package name="edu.nwu.dao"/>
    </mappers>
</configuration>

数据库配置文件:db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456

3、编写实体类文件:要在Teacher中体现一对多

package edu.nwu.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
package edu.nwu.pojo;

import lombok.Data;

import java.util.List;
@Data
public class Teacher {
    private int id;
    private String name;

    // 一个老师有多个学生
    private List<Student> students;

}

4、编写接口文件:

package edu.nwu.dao;

import edu.nwu.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TeacherMapper {
    // 获取老师
    List<Teacher> getTeacher1();

    // 获得指定老师下的所有学生及老师信息
    Teacher getTeacher(@Param("tid") int id);

    // 利用子查询来获得
    Teacher getTeacher2(@Param("tid") int id);

}

5、编写接口对应的TeacherMappl.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="edu.nwu.dao.TeacherMapper">

    <select id="getTeacher1" resultType="Teacher">
        select * from teacher;
    </select>

    <!--利用连接查询的方式来获取结果-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid = t.id and t.id = #{tid}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--复杂的属性,我们需要单独处理,
        对象:association;
        集合:collection;
        javaType="" 指定属性的类型!
        集合中的泛型信息,我们使用ofType获取
        -->
        <collection property="students" javaType="ArrayList" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>


    <!--利用子查询的方式来获得结果-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from teacher where id = #{tid}
    </select>

    <resultMap id="TeacherStudent2" type="Teacher">
        <result property="id" column="id"/>
        <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId" column="id"/>
    </resultMap>

    <select id="getStudentByTeacherId" resultType="Student">
        select * from student where tid = #{tid}
    </select>

</mapper>

6、编写测试文件进行单元测试:

@org.junit.Test
    public void test2(){
        SqlSession session = MybatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher techaer = mapper.getTeacher(1);
        System.out.println(techaer);
        session.close();
    }

执行结果:

Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])
@org.junit.Test
    public void test3(){
        SqlSession session = MybatisUtils.getSession();
        TeacherMapper mapper = session.getMapper(TeacherMapper.class);
        Teacher teacher2 = mapper.getTeacher2(1);
        System.out.println(teacher2);
    }

执行结果:

Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])

ResultMap小结:

1、所有我们无法直接返回结果的,都需要做ResultMap结果映射集

2、结果映射需要保证返回的对象的属性和数据库查询出来的字段一一对应

11. 在Mybatis中使用注解开发

在Mybatis中新建一个项目的惯性思维:(本质:我们想利用Java操作数据)

1、每一个数据库表都有对应的pojo类(实体类)

2、每一个实体类都有一个对应的Mapper接口

3、每一个Mapper接口都有一个对应的Mapper.xml文件。

注意:这些必须要重复做的事情,在未来的项目开发中,我们可以通过一些工具类来自动一键生成代码

面向接口编程的本质:就是为了解耦

1、增加系统的可扩展性

2、接口中的方法可以复用

3、利于分层开发

dao(mapper) --> daoIml ---> service(业务接口) -->serviceImpl(业务实现类) --> Controller(控制层) 

一旦使用注解开发,就可以省去XML的配置!每一个注解都对应一个标签:

  • 在接口方法上使用注解
  • 必须还要绑定到我们的MyBatis-Config中去(推荐是用扫描包的方法,通用性强 )

注解开发时需注意

  • 如果只有简单的增删改查的话,其实完全用注解就足够了,只不过复杂一点的SQL语句(连接,嵌套查询等),使用注解开发就很麻烦了。
  • 只使用注解的情况下,就可以删除掉*.xml文件了(与接口对应的)
  • 同时也要修改Mybatis核心配置文件中的mapper选项,将resources改为class,并且指向mapper下的接口。(使用包扫描比较合理,什么时候都能用)
  • *.xml文件可以和注解同时起作用。必须和接口绑定并且在xml和接口都需要绑定到mybatis核心配置文件。
  • 注解开发在Mybatis中并不是一个重点,在Spring中才会大量使用注解
  • 在Mybatis中使用注解开发违背了解耦的思想,本来修改SQL语句是不用修改代码文件的(保证代码的绝对安全性)。

示例:

0、创建普通Maven项目并添加一个Mybatis的依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8FpU7lF9-1582305117233)(MyBatis学习笔记.assets/image-20200221221953301.png)]

1、添加依赖:

<?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>edu.nwu</groupId>
    <artifactId>Mybatis-03</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
        </dependency>

        <dependency>
            <groupId> org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.8</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

2、编写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">
<configuration>

    <!--xml 中元素的标签上下位置是有要求的-->
    <!-- 将配置文件改为properties -->
    <properties resource="db.properties"/>

    <settings>
        <setting name="logImpl" value="NO_LOGGING"/>
        <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <!--<setting name="logImpl" value="LOG4J"/>-->
    </settings>

    <!--包的别名配置-->
    <typeAliases>
        <!-- 给包下所有类起别名 -->
        <package name="edu.nwu.pojo"/>
        <!-- 给一个类起别名 alias是自己起的别名-->
        <!--<typeAlias type="edu.nwu.pojo.User" alias="User"/>-->
    </typeAliases>

    <!--<environments default="development">-->
        <!--&lt;!&ndash;这里只是一个环境,还可以配置多个环境&ndash;&gt;-->
        <!--<environment id="development">-->
            <!--<transactionManager type="JDBC"/>-->
            <!--<dataSource type="POOLED">-->
                <!--<property name="driver" value="com.mysql.jdbc.Driver"/>-->
                <!--<property name="url" value="jdbc:mysql://localhost:3306/mybatis?-->
<!--useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>-->
                <!--<property name="username" value="root"/>-->
                <!--<property name="password" value="123456"/>-->
            <!--</dataSource>-->
        <!--</environment>-->
    <!--</environments>-->
    <!-- 一个environments 标签元素可以有多套配置 -->
    <environments default="development">
        <!-- 里面的每一个environment代表一个具体的环境 -->
        <environment id="development">
            <!--transactionManager 事务管理器 -->
            <transactionManager type="JDBC"/>
            <!-- dataSource 数据源配置 -->
            <dataSource type="POOLED">
                <!-- 连接数据库的配置i-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--<mapper resource="edu/nwu/mapper/UserMapper.xml"/>-->
        <!--<mapper resource="edu/nwu/mapper/UserMapperX.xml"/>-->
        <package name="edu.nwu.mapper"/>
    </mappers>
</configuration>

数据库相关配置文件:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=123456

3、编写接口类文件:(使用注解编写SQL语句,无序配置相应的*.xml文件了)

package edu.nwu.mapper;

import edu.nwu.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

public interface UserMapper {

    @Select("select * from user where id = #{id}")
    User getUser(int id);

    @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);

    @Insert("insert into user (`id`,`name`,`pwd`)values(#{id},#{name},#{pwd})")
    int addUser(User user);


    @Delete("delete from user where id = #{id}")
    int delUser(int id);
}

4、测试结果:(编写测试文件)

package edu.nwu.mapper;

import edu.nwu.pojo.User;
import edu.nwu.utils.MybatisUtils;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class UserMapperTest {

    @Test
    public void testGetUser(){
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.getUser(1);
        System.out.println(user);
    }

    @Test
    public void testUpdateUser(){
        SqlSession session = MybatisUtils.getSession(true);
        UserMapper mapper = session.getMapper(UserMapper.class);
        int result = mapper.updateUser(new User(1, "小哆", "666666"));
        System.out.println(result);
    }

    @Test
    public void testAddUser(){
        SqlSession session = MybatisUtils.getSession(true);
        UserMapper mapper = session.getMapper(UserMapper.class);
        int i = mapper.addUser(new User(8, "嘿嘿", "ssssss"));
        System.out.println(i);
    }

    @Test
    public void testDelUser(){
        SqlSession session = MybatisUtils.getSession(true);
        UserMapper mapper = session.getMapper(UserMapper.class);
        int i = mapper.delUser(1);
        System.out.println(i);

    }
}

小结

  • 利用注解开发在Mybatis中比操作 .xml要快捷的多
  • 但是功能很受限,一旦遇到复杂的查询,就必须转回使用 .xml进行配置。
13、动态SQL

参考:Mybatis动态SQL学习笔记,独立的一篇文章!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完整版:https://download.csdn.net/download/qq_27595745/89522468 【课程大纲】 1-1 什么是java 1-2 认识java语言 1-3 java平台的体系结构 1-4 java SE环境安装和配置 2-1 java程序简介 2-2 计算机中的程序 2-3 java程序 2-4 java类库组织结构和文档 2-5 java虚拟机简介 2-6 java的垃圾回收器 2-7 java上机练习 3-1 java语言基础入门 3-2 数据的分类 3-3 标识符、关键字和常量 3-4 运算符 3-5 表达式 3-6 顺序结构和选择结构 3-7 循环语句 3-8 跳转语句 3-9 MyEclipse工具介绍 3-10 java基础知识章节练习 4-1 一维数组 4-2 数组应用 4-3 多维数组 4-4 排序算法 4-5 增强for循环 4-6 数组和排序算法章节练习 5-0 抽象和封装 5-1 面向过程的设计思想 5-2 面向对象的设计思想 5-3 抽象 5-4 封装 5-5 属性 5-6 方法的定义 5-7 this关键字 5-8 javaBean 5-9 包 package 5-10 抽象和封装章节练习 6-0 继承和多态 6-1 继承 6-2 object类 6-3 多态 6-4 访问修饰符 6-5 static修饰符 6-6 final修饰符 6-7 abstract修饰符 6-8 接口 6-9 继承和多态 章节练习 7-1 面向对象的分析与设计简介 7-2 对象模型建立 7-3 类之间的关系 7-4 软件的可维护与复用设计原则 7-5 面向对象的设计与分析 章节练习 8-1 内部类与包装器 8-2 对象包装器 8-3 装箱和拆箱 8-4 练习题 9-1 常用类介绍 9-2 StringBuffer和String Builder类 9-3 Rintime类的使用 9-4 日期类简介 9-5 java程序国际化的实现 9-6 Random类和Math类 9-7 枚举 9-8 练习题 10-1 java异常处理 10-2 认识异常 10-3 使用try和catch捕获异常 10-4 使用throw和throws引发异常 10-5 finally关键字 10-6 getMessage和printStackTrace方法 10-7 异常分类 10-8 自定义异常类 10-9 练习题 11-1 Java集合框架和泛型机制 11-2 Collection接口 11-3 Set接口实现类 11-4 List接口实现类 11-5 Map接口 11-6 Collections类 11-7 泛型概述 11-8 练习题 12-1 多线程 12-2 线程的生命周期 12-3 线程的调度和优先级 12-4 线程的同步 12-5 集合类的同步问题 12-6 用Timer类调度任务 12-7 练习题 13-1 Java IO 13-2 Java IO原理 13-3 流类的结构 13-4 文件流 13-5 缓冲流 13-6 转换流 13-7 数据流 13-8 打印流 13-9 对象流 13-10 随机存取文件流 13-11 zip文件流 13-12 练习题 14-1 图形用户界面设计 14-2 事件处理机制 14-3 AWT常用组件 14-4 swing简介 14-5 可视化开发swing组件 14-6 声音的播放和处理 14-7 2D图形的绘制 14-8 练习题 15-1 反射 15-2 使用Java反射机制 15-3 反射与动态代理 15-4 练习题 16-1 Java标注 16-2 JDK内置的基本标注类型 16-3 自定义标注类型 16-4 对标注进行标注 16-5 利用反射获取标注信息 16-6 练习题 17-1 顶目实战1-单机版五子棋游戏 17-2 总体设计 17-3 代码实现 17-4 程序的运行与发布 17-5 手动生成可执行JAR文件 17-6 练习题 18-1 Java数据库编程 18-2 JDBC类和接口 18-3 JDBC操作SQL 18-4 JDBC基本示例 18-5 JDBC应用示例 18-6 练习题 19-1 。。。
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值