Mybatis学习笔记

2 篇文章 0 订阅
1 篇文章 0 订阅

一、简单实现操作

  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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>icu.yyykstudy</groupId>
    <artifactId>Mybatis-Study</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>mybatis-01</module>
    </modules>


    <!--导入依赖-->
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
        </dependency>
    </dependencies>

    <!--过滤静态资源-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

</project>
  1. 右键项目名 --> new --> Module — 创建一个项目

  2. src --> java下创建dao,pojo,utils包

  3. utils下创建MybatisUtils

package icu.yyykstudy.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;

//SqlSessionFactory --> SqlSession
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //第一步:获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

  1. pojo下创建User
package icu.yyykstudy.pojo;
public class User {
    private int id;
    private String name;
    private String pwd;
    public User() {
    }
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

  1. dao下创建UserMapper
package icu.yyykstudy.dao;

import icu.yyykstudy.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface UserMapper {
    public List<User> getUserList();

    public User getUserById(@Param("id") int id);

    public int insert(User user);

    public int update(User user);

    // 不加@Param也可以
    public int deleteById(int id);
}
  1. dao下创建UserMapper.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">
<!--namespace=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="icu.yyykstudy.dao.UserMapper">
    <select id="getUserList" resultType="icu.yyykstudy.pojo.User">
        select * from mybatis.user
    </select>

    <select id="getUserById" parameterType="int" resultType="icu.yyykstudy.pojo.User">
        select *
        from mybatis.user
        where id = #{id};
    </select>

    <insert id="insert" parameterType="icu.yyykstudy.pojo.User">
        insert into mybatis.user(id, name, pwd)
        values (#{id},#{name},#{pwd});
    </insert>

    <update id="update" parameterType="icu.yyykstudy.pojo.User">
        update mybatis.user
        set name = #{name},pwd = #{pwd}
        where id = #{id};
    </update>

    <delete id="deleteById" parameterType="int">
        delete from mybatis.user where id = #{id};
    </delete>

</mapper>
  1. 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:核心配置文件-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT%2B8"/>
                <property name="username" value="lyyykstudy"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

<!--    每一个Mapper.xml都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="icu/yyykstudy/dao/UserMapper.xml"></mapper>
    </mappers>
</configuration>
  1. 测试
package icu.yyykstudy.dao;

import icu.yyykstudy.pojo.User;
import icu.yyykstudy.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {

    @Test
    public void getUserList(){
		//1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);  //将配置文件中的property和mapper对应的class或resouce中的Mapper打包到Configuration中

        //3.使用工厂生产SqlSession对象
        SqlSession sqlSession = factory.openSession();
        try{

            //4.使用SqlSession创建Dao接口的代理对象并执行方法
            /*方式一:getMapper //生成一个代理对象  
            public <T> T getMapper(Class<T> daoInterfaceClass) {
        		return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),new Class[]{daoInterfaceClass},new MapperProxy(cfg.getMappers(),connection));
    		}
            */
            UserMapper mapper = sqlSession.getMapper(UserMapper.class); 
            //使用代理对象执行方法
            List<User> userList = mapper.getUserList();

            //方式二:不生成代理对象,可以自己写一个实现UserMapper接口的类,但是这样很麻烦,不如直接代理
            List<User> userList = sqlSession.selectList("icu.yyykstudy.dao.userdao.getUserList");  //类名+方法名icu.yyykstudy.dao.userdao.getUserList	


            for (User user : userList) {
                System.out.println(user);
            }
        }finally {
        	//5.释放资源
	        in.close();
            sqlSession.close();
        }
    }

//也可这样写,调用MybatisUtils下的getSqlSession()方法
	@Test
    public void getUserList(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            //第二步:执行SQL
            //方式一:getMapper
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            List<User> userList = mapper.getUserList();
            //方式二:老方法,不建议写
//        List<User> userList = sqlSession.selectList("icu.yyykstudy.dao.userdao.getUserList");
            for (User user : userList) {
                System.out.println(user);
            }
        }finally {
            sqlSession.close();
        }
    }

    //增删改需要提交事务
    @Test
    public void insert(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int res = mapper.insert(new User(3, "赵五", "123456"));
            if(res>0){
                System.out.println("插入成功");
                sqlSession.commit();
            }else
                sqlSession.rollback();

        }finally {
            sqlSession.close();
        }
    }

    @Test
    public void update(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int res = mapper.update(new User(3, "王五", "123456"));
            if(res>0){
                System.out.println("更新成功");
                sqlSession.commit();
            }else
                sqlSession.rollback();

        }finally {
            sqlSession.close();
        }
    }

    @Test
    public void delete(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try{
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            int res = mapper.deleteById(3);
            if(res>0){
                System.out.println("删除成功");
                sqlSession.commit();
            }else
                sqlSession.rollback();
        }finally {
            sqlSession.close();
        }
    }
}

二、入门知识点

首先实体类的属性名须和数据库名一样,否则很麻烦,后面有讲

1. parameterType:接受参数类型(多用于增删改)
· 基本类型:如int,Integer,java.lang.Integer
· 实体类型:icu.yyykstudy.pojo.User

2. resultType:返回类型(多用于查询)
· 基本类型:如int,Integer,java.lang.Integer
· 实体类型:icu.yyykstudy.pojo.User

3. resultMap:结果集映射,只能解决结果集返回时类属性名和数据库字段名不匹配问题,并不能解决传值时的问题

	<!-- 定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id> <!-- 主键ID-->
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account">
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>

3. #{“value”}中的value
· 基本类型:若方法只有一个参数写什么名字都行,若有很多可在方法名的参数前加@Param(“value”)来区分
· 实体类型:User中的get,set方法必须是自动生成的!!!直接写属性名!若User中还有Animal实体类对象,可以通过animal.name得到其属性值。

4. 通过注解或映射文件代理Dao接口

<mappers>
    <mapper resource="icu/yyykstudy/dao/IUserDao.xml"/>	<!-- 使用映射配置文件 -->
	<mapper class="icu.yyykstudy.dao.IUserDao"/>  <!-- 使用注解 -->
</mappers>

5.配置别名
在 mybatis-config.xml 中配置:

定义pojo下的类名

<typeAliases>
<!-- 单个别名定义 --> 
<typeAlias alias="user" type="icu.yyyksutdy.pojo.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) --> 
	<package name="com.itheima.domain"/>
	<package name="其它包"/>
</typeAliases>

定义mapper(dao)包下的类名

<!---->
<mapper resource="com/itheima/dao/IUserDao.xml" />
<mapper class="com.itheima.dao.UserDao"/>
<!--★注意:此种方法要求mapper接口名称和mapper映射文件名称相同,且放在同一个目录中。-->

6.对于SQL语句中含有where且有未知判断参数用if标签

在映射配置文件UserMapper.xml中使用if语句判断判断的有什么参数

<select id="findUserByCondition" resultMap="userMap" parameterType="user">
	select * from user where 1=1
    <if test="userName != null">
        and username = #{userName}
    </if>
    <if test="userSex != null">
        and sex = #{userSex}
    </if>
</select>

也可不用写where 1=1,那在配置文件的if标签前加where标签

<select id="findUserByCondition" resultMap="userMap" parameterType="user">
	select * from user 
	<where>
		<if test="usersame != null">
			and username = #{userName}
        </if>
        <if test="usersex != null">
            and sex = #{userSex}
        </if>
	</where>
</select>

foreach标签
用来遍历SQL语句中一个属性中多个值

List<User> findUserInIds(QueryVo vo);  //QueryVo ---> private List<Integer> ids;
<!-- 了解的内容:抽取重复的sql语句-->
<sql id="defaultUser">
	select * from user
</sql>
<select id="findUserInIds" resultMap="userMap" parameterType="queryvo">
	<include refid="defaultUser"></include> <!-- select * from user -->
	<where>
		<if test="ids != null and ids.size()>0">
        	<foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
            	#{uid}
            </foreach>
        </if>
	</where>
</select>

collection为遍历集合
item为集合中的每一个值
open,close只执行一次,分别为开头和结束
separator为分隔符

三、知识点

1.模糊查询

第一种:简单字符串拼接

List<User> list = mapper.queryByname("%"+name+"%");
<select id="queryByname" parameterType="string" resultType="icu.yyykstudy.pojo.User">
	select * from user where username like #{name}
</select>

第二种:

List<User> list = udao.queryByname(name);
<select id="queryByname" parameterType="string" resultType="icu.yyykstudy.pojo.User">
	select * from user where username like '%${value}%'  //⭐若传入一个变量此处只能写value,与底层代码有关,若传入一个实体类,可通过聚合函数concat('%',#{},'%')实现
</select>

第二种更为好用,防止SQL注入
两种方法比较

2.得到插入后的ID

数据库中查询新插入的ID的SQL语句

select last_insert_id();

在配置文件中

<insert id="insert" parameterType="icu.yyykstudy.pojo.User">
	<selectKey keyProperty="id" keyColumn="id" order="AFTER" resultType="int"> //keyColumn:属性名  keyColumn:数据库字段名
		select last_insert_id(); 
	</selectKey>
	insert into user(username) value (#{name}); 
</insert>
	User user = new User("小狗");
	udao.insert(user);	//执行此方法后,user中的id由null变为刚插入的id值
3.类属性名和数据库字段名不匹配问题

在映射文件中添加

	<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
    <resultMap id="userMap" type="icu.yyykstudy.pojo.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>
4.mybatis连接池

Mybatis将它自己的数据源分为三类:

 UNPOOLED   不使用连接池的数据源
 POOLED     使用连接池的数据源 
 JNDI       使用JNDI 实现的数据源(见7)

在dataSouce的type属性中修改

<!-- 配置数据源(连接池)信息 --> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>

MyBatis 在初始化时,根据dataSource的 type 属性来创建相应类型的的数据源 DataSource,即:

type=“POOLED”:MyBatis 会创建 PooledDataSource 实例
type=“UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=“JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

PooledDataSource工作原理
PooledDataSource工作原理

5.mybatis事务
session = factory.openSession(true); //事务关自动提交,底层就是JDBC的connection.setAutoCommit(false)
6.mybatis中pojo包建类思想
一对一

一个账户有一个用户

Account类

	private Integer id;
    private Integer uid;
    private Double money;

    //从表实体应该包含一个主表实体的对象引用
    private User user;

AccountMapper.xml中

	<!-- 定义封装account和user的resultMap -->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一的关系映射:配置封装user的内容-->
        <association property="user" column="uid" javaType="user">
            <id property="id" column="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </association>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from account a , user u where u.id = a.uid;
    </select>
一对多

一个用户有多个账户

User:

	private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //一对多关系映射:主表实体应该包含从表实体的集合引用
    private List<Account> accounts;

UserMapper.xml中

	<!-- 定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account">
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>
多对多

多个人对应多个角色

实体类
User

	private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //多对多的关系映射:一个用户可以具备多个角色
    private List<Role> roles;

Role

	private Integer roleId;
    private String roleName;
    private String roleDesc;

    //多对多的关系映射:一个角色可以赋予多个用户
    private List<User> users;

映射文件
IUserMapper.xml

	<!-- 定义User的resultMap-->
    <resultMap id="userMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置角色集合的映射 -->
        <collection property="roles" ofType="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="userMap">
        select u.*,r.id as rid,r.role_name,r.role_desc from user u
         left outer join user_role ur  on u.id = ur.uid
         left outer join role r on r.id = ur.rid
    </select>

IRoleMapper.xml

	<!--定义role表的ResultMap-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </collection>
    </resultMap>

    <!--查询所有-->
    <select id="findAll" resultMap="roleMap">
       select u.*,r.id as rid,r.role_name,r.role_desc from role r
        left outer join user_role ur  on r.id = ur.rid
        left outer join user u on u.id = ur.uid
    </select>

其次,数据库中也要有对应的两个表user,role,和一个中间表user_role,并且得有外键,一对多也要有外键,最好不要用物理外键,在代码中写比较。

7.创建JNDI项目
  1. 创建web项目
  2. META-INF下创建context.xml
    META-INF下创建context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- 
<Resource 
name="jdbc/eesy_mybatis"						数据源的名称
type="javax.sql.DataSource"						数据源类型
auth="Container"								数据源提供者
maxActive="20"									最大活动数
maxWait="10000"									最大等待时间
maxIdle="5"										最大空闲数
username="root"									用户名
password="1234"									密码
driverClassName="com.mysql.jdbc.Driver"			驱动类
url="jdbc:mysql://localhost:3306/eesy_mybatis"	连接url字符串
/>
 -->
<Resource 
name="jdbc/eesy_mybatis"
type="javax.sql.DataSource"
auth="Container"
maxActive="20"
maxWait="10000"
maxIdle="5"
username="root"
password="1234"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/eesy_mybatis"
/>
</Context>
  1. mybatis-config.xml中dataSource中配置JNDI
	<!-- 配置mybatis的环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境 -->
        <environment id="mysql">
            <!-- 配置事务控制的方式 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的必备信息  type属性表示是否使用数据源(连接池)-->
            <dataSource type="JNDI">
                <property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"/>
            </dataSource>
        </environment>
    </environments>
  1. jsp中测试
<html>
<body>
<h2>Hello World!</h2>
<%
    //1.读取配置文件
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2.根据配置文件构建SqlSessionFactory
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(in);
    //3.使用SqlSessionFactory创建SqlSession对象
    SqlSession sqlSession = factory.openSession();
    //4.使用SqlSession构建Dao的代理对象
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    //5.执行dao中的findAll方法
    List<User> users = userDao.findAll();
    for(User user : users){
        System.out.println(user);
    }
    //6.释放资源
    sqlSession.close();
    in.close();
%>
</body>
</html>
8.延迟加载
	问题:
		在一对多中,当我们有一个用户,它有100个账户。
		在查询用户的时候,要不要把关联的账户查出来?
		在查询账户的时候,要不要把关联的用户查出来?
		在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的。
		在查询账户时,账户的所属用户信息应该是随着账户查询时一起查询出来。
	
	什么是延迟加载?
		在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
	什么是立即加载?
		不管用不用,只要一调用方法,马上发起查询。
		
	在对应的四种表关系中:一对多,多对一,一对一,多对多
		一对多,多对多:通常情况下我们都是采用延迟加载。
		多对一,一对一:通常情况下我们都是采用立即加载。
  1. 在mybatis配置中开启懒加载
	<!--配置参数-->
    <settings>
        <!--开启Mybatis支持延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>

配置详解

  1. 在mapper.xml文件中封装类

一对一

IAccountDao.xml

	<resultMap id="accountUserMap" type="account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 一对一的关系映射:配置封装user的内容
        select属性指定的内容:查询用户的唯一标识:
        column属性指定的内容:用户根据id查询时,所需要的参数的值
        -->
        <association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"></association>
    </resultMap>

	<!-- 查询所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select * from account
    </select>

UserDao.xml

	<!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="user">
        select * from user where id = #{uid}
    </select>

一对多

UserDao.xml

	<resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <!-- 配置user对象中accounts集合的映射 -->
        <collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select * from user
    </select>

IAccountDao.xml

 	<!-- 根据用户id查询账户列表 -->
    <select id="findAccountByUid" resultType="account">
        select * from account where uid = #{uid}
    </select>
  1. 测试
	public void testFindAll(){
		List<Account> accounts = accountDao.findAll();
	    }
	}

在这里插入图片描述

	public void testFindAll(){
		List<Account> accounts = accountDao.findAll();
	    for(Account account : accounts){
	        System.out.println("--------每个account的信息------------");
	        System.out.println(account);
	        System.out.println(account.getUser());
	    }
	}

需要用到查询每个user时

很显然,第一次没有用到查询用户的方法,就没有查询信息,用到的时候再一条一条地查询
9.缓存
	什么是缓存
		存在于内存中的临时数据。
	为什么使用缓存
		减少和数据库的交互次数,提高执行效率。
	什么样的数据能使用缓存,什么样的数据不能使用
	适用于缓存:
		经常查询并且不经常改变的。
		数据的正确与否对最终结果影响不大的。
	不适用于缓存:
		经常改变的数据
		数据的正确与否对最终结果影响很大的。
		例如:商品的库存,银行的汇率,股市的牌价。
	Mybatis中的一级缓存和二级缓存
		一级缓存:
			它指的是Mybatis中SqlSession对象的缓存。
			当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中。
			该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中
			查询是否有,有的话直接拿出来用。
			当SqlSession对象消失时,mybatis的一级缓存也就消失了。
		
		二级缓存:
			它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。
			二级缓存的使用步骤:
				第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
				第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
				第三步:让当前的操作支持二级缓存(在select标签中配置)

一级缓存

		User user1 = userDao.findById(41);
        System.out.println(user1);
		User user2 = userDao.findById(41);
		System.out.println(user1 == user2);	//true
//      sqlSession.close();
        //再次获取SqlSession对象
//        sqlSession = factory.openSession();

        sqlSession.clearCache();//此方法也可以清空缓存

        userDao = sqlSession.getMapper(IUserDao.class);

        User user3 = userDao.findById(41);
        System.out.println(user3);

        System.out.println(user1 == user3);	//false
		//1.根据id查询用户
        User user1 = userDao.findById(41);
        System.out.println(user1);

        //2.更新用户信息
        user1.setUsername("update user clear cache");
        user1.setAddress("北京市海淀区");
        userDao.updateUser(user1);

        //3.再次查询id为41的用户
        User user2 = userDao.findById(41);
        System.out.println(user2);

        System.out.println(user1 == user2);//false
        /*
        	※一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit()
        方法时,就会清空一级缓存。close()等
        */

二级缓存

结构图
二级缓存结构图

  1. mybatis配置文件
	<settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
  1. Mapper配置文件
<!--开启user支持二级缓存-->
	<mapper namespace="com.itheima.dao.IUserDao">
	    <!--开启user支持二级缓存-->
	    <cache/>
	</mapper>
  1. Mapper方法标签
	<select id="findById" parameterType="INT" resultType="user" useCache="true">
        select * from user where id = #{uid}
    </select>

注:二级缓存存放的是数据而不是对象,因此查出来的对象地址并不相同。

10.注解开发

1.解决类属性名与数据库名不同

	@Select("select * from user")
    @Results(id="userMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
    })
    List<User> findAll();
    //这里的Results只需配置一次即可,其他方法可根据id直接引用,后面有用到。

2.一对一

IAccountDao

	@Select("select * from account")
    @Results(id="accountMap",value = {
            @Result(id=true,column = "id",property = "id"),
            @Result(column = "uid",property = "uid"),
            @Result(column = "money",property = "money"),
            @Result(property = "user",column = "uid",one=@One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
    })
    List<Account> findAll();

IUserDao

@Select("select * from user  where id=#{id} ")
    @ResultMap("userMap")
    User findById(Integer userId);

3.一对多

IUserDao

	@Select("select * from user")
    @Results(id="userMap",value={
            @Result(id=true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
            @Result(property = "accounts",column = "id",
                    many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
                                fetchType = FetchType.LAZY))
    })
    List<User> findAll();

IAccountDao

 	@Select("select * from account where uid = #{userId}")
    List<Account> findAccountByUid(Integer userId);

4.缓存

一级缓存自动开
二级缓存:
1.mybatis配置文件中配置二级缓存,9中有(不用配置也可,默认开启)
2.mapper接口中加一个注解即可

@CacheNamespace(blocking = true)
public interface IUserMapper {

}

四、一些JDBC知识点

PreparedStatement对象的执行方法
  • execute:它能执行CRUD中的任意一种语句。它的返回值是一个boolean类型,表
    示是否有结果集。有结果集是true,没有结果集是fasle。
  • executeUpdate:它只能执行CUD语句,查询语句无法执行。他的返回值是影响数
    据库记录的行数
  • executeQuery:它只能执行SELECT语句,无法执行增删改。执行结果封装的结果集ResultSet对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值