mybatis

1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
		1.导入jar包
    	log4j日志包
      mysql驱动包
      mybatis的jar包
    2.导入配置文件
      log4j日志包
      mybatis核心配置文件 xml
      sql映射文件
    3.编写代码
      传统方式:
					配置完核心配置文件后
					直接在sql映射文件中编写sql语句
          调用sqlSession的API,指定sql语句,执行方法
      动态代理方式:
					配置完核心配置文件后
					在sql映射文件中编写sql语句
          编写dao层的接口
          调用sqlSession的getMapper方法,生成接口的实现类(代理类),
					在代理类中调用Sqlsession的相关方法完成增删改查
API:
		SqlSessionFactoryBuilder: 解析
      	作用: 解析配置文件(核心配置文件,sql映射文件)
        方法: build(is);
		SqlSessionFactory: 线程安全(内部没有共享的变量)
      	作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
        方法: openSession(boolean);
		SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
				作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
        方法:
						selectList("namespace.id",参数);
						selectOne("namespace.id",参数);
						insert("namespace.id",参数);
						update("namespace.id",参数);
            delete("namespace.id",参数);
						rollback();
						commit();
						close();
						T getMapper(T.class);
								底层使用动态代理,生成接口的实现类,
								在接口的实现类方法中调用以上方法完成增删改查

Mybatis

作用: 对jdbc进行了封装,将sql语句与java代码分离

一 传统方式实现Mybatis

程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)

入门实现

1.导入jar包

2.准备mybatis的配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

sql映射文件-user

<?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: 区分多个sql映射文件
-->
<mapper namespace="user">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="user">
		select *  from user
	</select>

    <!-- select 一条记录 -->
    <select id="queryOne" resultType="user" parameterType="int">
		select *  from user where id = #{id}
	</select>

</mapper>

sql映射文件-product

<?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: 区分多个sql映射文件
-->
<mapper namespace="product">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="product">
		select *  from product
	</select>

</mapper>

启动解析过程

xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
  String url;
	String driver;
	String username;
	String password;
	Map<String,Mapper>
        key:String,存放当前sql的唯一标识
            sql语句标签上id属性的值
            命名空间.id
        value: Mapper,当前的sql语句及返回值对象
        
Mapper.java  一个sql语句对应一个Mapper
  String sql; // 配置文件中的sql语句
	String resultType; // sql执行后返回的数据类型
	String parameterType; // sql执行时需要传入的参数类型

3.编写自己的业务

mybatis提供的相关API方法

Mybatis封装好的方法:
	SqlSession提供操作数据库的方法
		参数1: mapperId = namespace.id; 找到对应的sql语句
    参数2: 执行当前sql需要使用的参数
    selectList("mapperId",参数...);
		selectOne("mapperId",参数...);
		insert("mapperId",参数...);
		update("mapperId",参数...);
		delete("mapperId",参数...);
	在以上方法中封装了JDBC操作
    commit();
		rollback();
		close();
		创建接口的实现类对象(代理类)
		getMapper(Class ...);

user业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
    List<User> findAll() throws IOException;
    User findById(int id);
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

/**
 * 传统方式:
 *      手动调用Mybatis提供的方法,完成增删改查
 */
public class UserMapperImpl implements UserMapper {

    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        MybatisUtils.close(sqlSession);
        return user;
    }

   /* private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        return user;
    }*/

}

product业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
    List<Product> findAll();
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

public class ProductMapperImpl implements ProductMapper {

    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }



    /*private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        sqlSession.close();
        return list;
    }*/
}

Mybatis工具类

package com.itheima.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 {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象(默认手动提交事务)
     * @return
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 根据传递的参数,返回具体的sqlSession对象
     * @param flag
     * @return
     */
    public static SqlSession getSqlSession(boolean flag){
        return sqlSessionFactory.openSession(flag);
    }

    public static void close(SqlSession sqlSession){
        if (sqlSession!=null){
            sqlSession.close();
        }
    }
}

Log4j日志

1.导入jar包
2.导入配置文件 

二 动态代理方式实现Mybatis★

程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行 
约定大于配置:
		框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定: 
		mybatis在定位sql语句时,使用的是  接口的全限定名.方法名称
    	例子: 查找findAll方法调用的sql语句
			com.itheima.dao.UserDao.findAll

代码实现

1.导入jar包

2.编写配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

3.编写我们的逻辑

user接口

package com.itheima.dao;

import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    // 查询所有用户信息
    List<User> findAll();
    // 根据id查询
    User findById(int id);

    // 添加
    int insertUser(User user);
    int insertUser1(User user);
    // 修改
    int updateUser(Map<String,Object> userMap);
     删除
    int deleteUser(int id);
    // 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
    List<User> findUserByMohu(@Param("name") String username);

    /**
     * 将user表中的数据封装到对应的Person中
     * @return
     */
    List<Person> findUserToPerson();

    /**
     * 参数罗列时,必须给参数起别名
     * @param username
     * @param sex
     * TODO: 请求参数有多个时,必须起别名
     * @return
     */
    List<User> findUserByTiaojian(@Param("username") String username,
                                  @Param("sex") String sex);

    /**
     * 动态sql进行修改
     * @return
     */
    int updateUser1(User user);

    /**
     * 请求参数为数组
     * @param ids
     * @return
     */
    List<User> findUserByIds1(int[] ids);
    List<User> findUserByIds2(List<Integer> ids);
}

sql映射文件

<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
    TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
    TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
    <!-- select 查询所有 -->
	<select id="findAll" resultType="user">
		select *  from user
	</select>
	<!--
		select标签: 表示查询,用于描述查询的sql语句
		id: 唯一标识,找到唯一的一条sql语句
		parameterType: 请求参数的类型
		resultType: 返回值类型
			返回值的全限定名(也可以使用别名)
		TODO:获取请求参数: 在sql中获取请求携带的参数值
			OGNL表达式: 获取请求携带的参数值
				格式:
					#{} : 占位符,底层使用PreparedStatement执行sql语句
					${} : 字符串拼接,底层使用Statement执行sql语句
				请求参数类型:
					基本类型或String:
						#{随便写}
						${value}
					pojo实体对象
						#{属性名}
					list
					map
					...
	-->
	<!--<select id="findById" parameterType="int" resultType="user">
		select * from user where id = #{随便写}
	</select>-->
	<select id="findById" parameterType="int" resultType="user">
		select * from user where id = ${value}
	</select>
	<!--
		增删改,默认返回int(影响的行数),此返回值不需要设置
		OGNL: 获取pojo对象中的数据
			#{属性名}
	-->
	<!--
		resultType: 主键类型
		keyColumn: 主键字段名称
		keyProperty: 将查询结果赋给实体对象中的哪个属性
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	-->
	<insert id="insertUser" parameterType="user">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	</insert>
	<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
	</insert>
	<!-- 修改操作:
	 	OGNL表达式: 获取map中的值
	 		#{map的key}
	 -->
	<update id="updateUser" parameterType="map">
		update user set username=#{username},birthday=#{birthday},
		sex=#{sex},address=#{address} where id=#{id}
	</update>

	<!-- 删除 -->
	<delete id="deleteUser" parameterType="int">
		delete from user where id = #{id}
	</delete>

	<!-- 模糊查询 -->
	<select id="findUserByMohu" parameterType="string" resultType="user">
		select * from user where username like concat("%",#{name},"%");
	</select>

	<!-- 别名查询,将查询结果封装到指定对象中 -->
	<!--<select id="findUserToPerson" resultType="Person">
		SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
	</select>-->
	<select id="findUserToPerson" resultMap="userToPersonMap">
		SELECT * FROM user ;
	</select>
	<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
	<resultMap id="userToPersonMap" type="Person">
		<id column="id" property="pid"></id>
		<result column="username" property="pusername"></result>
		<result column="birthday" property="pbirthday"></result>
		<result column="sex" property="psex"></result>
		<result column="address" property="paddress"></result>
	</resultMap>

	<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
	 	select * from user
		select * from user where username like concat('%',#{username},'%')
		select * from user where sex = #{sex}
		select * from user where username like concat('%',#{username},'%') and sex = #{sex}
	 -->
	<select id="findUserByTiaojian" resultType="User">
		select * from user
		<where>
			<if test="username!=null and username!=''">
				and username like concat('%',#{username},'%')
			</if>
			<if test="sex!=null and sex!=''">
				and sex = #{sex}
			</if>
		</where>
	</select>

	<!-- 动态修改 -->
	<update id="updateUser1" parameterType="User">
		update user
		<set>
			<if test="username!=null and username!=''">
				username=#{username},
			</if>
			<if test="birthday!=null and birthday!=''">
				birthday=#{birthday},
			</if>
			<if test="sex!=null and sex!=''">
				sex=#{sex},
			</if>
			<if test="address!=null and address!=''">
				address=#{address},
			</if>
		</set>
		where id=#{id}
	</update>
	<!-- 遍历数组 -->
	<select id="findUserByIds1" parameterType="int[]" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="array" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>

	<!-- 遍历list集合 -->
	<select id="findUserByIds2" parameterType="list" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="list" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>
</mapper>

测试代码

package com.itheima.test;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.*;

public class TestMybatis {

    @Test
    public void test01_FindAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findAll();
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test02_findById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = mapper.findById(5);
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 需求: 添加完毕后,获取最新添加的数据的id值
     */
    @Test
    public void test03_insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("托塔李天王1");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("陈塘关");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }
    @Test
    public void test03_insertUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("嫦娥");
        user.setSex("女");
        user.setBirthday(new Date());
        user.setAddress("月宫");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 修改
     */
    @Test
    public void test04_updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        Map<String, Object> map = new HashMap<>();
        map.put("id",14);
        map.put("username","玉皇大帝");
        map.put("sex","男");
        map.put("birthday",new Date());
        map.put("address","天庭");
        int i = mapper.updateUser(map);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test05_deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int i = mapper.deleteUser(10);
        if(i>0){
            System.out.println("删除成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test06_findUserByMohu(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByMohu("精");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test07_findUserToPerson(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Person> list = mapper.findUserToPerson();
        for (Person person : list) {
            System.out.println(person);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test08_findUserByTiaojian(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByTiaojian("精","女");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test09_updateUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setId(15);
        user.setUsername("嫦娥");
        user.setSex("男");
        user.setAddress("月亮之上");
        int i = mapper.updateUser1(user);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test10_findUserByIds1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int []arr = {1,3,4,5,6};
        List<User> list = mapper.findUserByIds1(arr);
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test11_findUserByIds2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(6);
        List<User> list2 = mapper.findUserByIds2(list);
        for (User user : list2) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }
}

Mybatis核心API

SqlSessionFactoryBuilder: 
	1.解析核心配置文件,以及关联的sql映射文件
	2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
	1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
	1.封装了jdbc操作,增删改查
		selectList("sql语句的id");
		selectOne("...",参数);
		insert("...");
		update("...");
		delete("...");
    2.getMapper
    	生成dao接口的实现类对象(代理类)
    3.事务控制的方法
    	commit();
    	rollback();
    	close();
    sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
	Conn conn;
	// 第一个线程 : 1 张三
	// 第二个线程 : 1 王五
	public int update(String name ,int id ){
		update 表名 set name = ? where 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">
<!--namespace(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user;
    </select>
    <!--
        parameterType: 传入参数类型
            可以传递的参数类型
                基本数据类型 和 String
                pojo对象
                数组
                list
                map
            编写格式:
                以上类型的全限定名
                    基本数据类型 和 String: 直接编写类型名称: int _int
                    pojo对象: com.itheima.pojo.User
                    数组: _int[] int[]
                    list: list
                    map: map
       ognl表达式:
            #{变量名称}: 占位符
                preparedStatement
                pojo: 实体对象的属性名称
            ${变量名称}: 字符串拼接
                Statement: 存在sql注入的风险
    -->
    <insert id="insertUser" parameterType="com.itheima.pojo.User">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
    </insert>
    <!-- 添加完成后,返回新增记录的id值
        useGeneratedKeys: 开启获取主键自增的值 开关
        keyColumn: 数据库主键字段名称
        keyProperty: 实体中属性的名称
     -->
    <insert id="insertUser1" parameterType="com.itheima.pojo.User"
     useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
        <!-- 返回新增记录的id值
             keyColumn: 数据库主键字段名称
             keyProperty: 实体中属性的名称
             resultType: 返回值类型
             order: 添加记录前或后
        -->
       <!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
              select last_insert_id();
        </selectKey>-->
    </insert>

    <!-- 修改
            出入参数: map
                #{map的key}
    -->
    <update id="updateUser" parameterType="map">
        update user
        set
          username=#{username},
          address=#{address},
          sex=#{sex},
          birthday=#{birthday}
        where id = #{id}
    </update>

    <!-- 当传入参数为一个基本类型或String时,
        #{随便写}
        最好见名知意
     -->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

    <!--
        如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
    -->
    <select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
        <!-- select * from user where username like '%${name}%' -->
        select * from user where username like concat('%',#{name},'%');
    </select>

    <!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
    <select id="findUserToPerson" resultMap="findUserToPersonMap">
        select * from user;
    </select>
    <!-- id: 当前resultMap的唯一标识
         type: 将当前的一条查询结果封装的对象类型
     -->
    <resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
        <!-- column: 数据库字段名称
             property: 实体属性名称
         -->
        <id column="id" property="pid"></id>
        <result column="username" property="pusername"></result>
        <result column="birthday" property="pbirthday"></result>
        <result column="sex" property="psex"></result>
        <result column="address" property="paddress"></result>
    </resultMap>
</mapper>

sql映射文件中的相关配置

作用: 主要用于编写sql语句
传入参数: 
	属性: parameterType
返回结果:
	属性: resultType 
	属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
	如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
    基本类型和String: 直接使用对应类型的类型名称即可
      int long
		pojo类型: 编写pojo的全限定名
			全限定名= 包名+类名;
					com.itheima.pojo.User
    	使用别名(别名需要在核心配置文件中进行配置)
		map: map
		list: list
		数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
		在idea中按两次 shift 键
		TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
    格式:
       #{变量名称}: 占位符,preparedStatement
            pojo: 实体对象的属性名称
        		map: 通过map的key获取value的值
        		基本类型或String:
        			  #{随便定义} : 最好见名知意
        		list: 动态sql遍历
        		数组: 动态sql遍历
        ${变量名称}: 字符串拼接,Statement,存在sql注入的风险
        		基本类型或String:
        			${value} : 固定值
     可以在参数列表中使用@Param("别名")给传入的参数起别名

动态sql

<!-- 抽取公共的sql语句 -->
    <sql id="userSql">
        select * from user
    </sql>
    <!-- 多条件查询 -->
    <select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
        <!-- 引用公共的sql语句 -->
        <include refid="userSql"></include>
        <where>
            <if test="username!=null and username!=''">
                and username like concat('%',#{username},'%')
            </if>
            <if test="sex!=null and sex!=''">
                and sex = #{sex}
            </if>
        </where>
    </select>

    <update id="updateUser1" parameterType="com.itheima.pojo.User">
        update user
        <set>
            <if test="username!=null and username!='' ">
                username=#{username},
            </if>
            <if test="address!=null and address!='' ">
                address=#{address},
            </if>
            <if test="sex!=null and sex!='' ">
                sex=#{sex},
            </if>
            <if test="birthday!=null">
                birthday=#{birthday}
            </if>
        </set>
        where id = #{id}
    </update>

    <select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="array" item="id" open="(" close=")" separator=",">
                 #{id}
            </foreach>
        </where>
    </select>

    <select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="list" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

多表查询

一对一

-- 创建用户基本表  User实体
drop table if exists user;
-- 创建用户基本表
create table user (
  id int primary key auto_increment,
  username varchar(20) not null,
  birthday date,
  sex char(1) default '男',
  address varchar(50)
);

insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
    
 -- 用户描述信息表   UserInfo实体
     create table user_info (
       id int primary key,   -- 既是主键又是外键
       height double,  -- 身高厘米
       weight double,   -- 体重公斤
       married tinyint,    -- 是否结婚,1为结婚,0为未婚
       foreign key (id) references user(id)
     );
 -- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
     
-- ========================== java对象
     User.java   封装用户的信息以及对应的描述信息
         private id
         private username
         private birthday
         private sex
         private address
         private UserInfo userInfo; 
     UserInfo.java  封装用户的描述信息,以及对应的用户信息
         id
         height
         weight
         married
         User user;
     多表查询的结果我们可以采用java的实体嵌套

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <select id="findUserAndUserInfo" resultMap="resultMap1">
        SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
        FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对一的映射数据信息 -->
        <association property="userInfo">
            <id column="uiid" property="id"></id>
            <result column="height" property="height"></result>
            <result column="weight" property="weight"></result>
            <result column="married" property="married"></result>
        </association>
    </resultMap>
</mapper>

一对多

-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
-- 创建订单表
    create table orders(
        oid int primary key auto_increment ,   -- 主键
        user_id int not null,   -- 用户id,外键
        number varchar(20),   -- 订单编号
        create_time datetime,  -- 下单时间
        note varchar(100),   -- 备注
        foreign key(user_id) references user(id)   -- 外键约束,关联主表的主键
    );
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');

	User.java   封装用户信息以及对应的订单信息
         private id
         private username
         private birthday
         private sex
         private address
         // 存放当前用户所拥有的多个订单
         private List<Orders> ordersList;
    Orders.java
    	 oid
    	 user_id
    	 number
    	 create_time
    	 note
  	在一对多查询时,在一的一方提供多的一方的实体List集合

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndOrders" resultMap="resultMap1">
        SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="ordersList" javaType="list" ofType="orders">
            <id column="oid" property="oid"></id>
            <result column="user_id" property="user_id"></result>
            <result column="number" property="number"></result>
            <result column="create_time" property="create_time"></result>
            <result column="note" property="note"></result>
        </collection>
    </resultMap>
</mapper>

多对多

	-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
      -- 角色
    CREATE TABLE `role` (
      role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
      role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
      role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
    );
    -- 插入角色记录
    INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
    INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
    INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
    INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
     -- 中间表
    CREATE TABLE user_role (
       user_id INT NOT NULL  COMMENT '用户id',
       role_id INT NOT NULL  COMMENT '角色id',
       PRIMARY KEY (user_id,role_id),  -- 复合主键
       FOREIGN KEY (user_id) REFERENCES `user`(id),   
       FOREIGN KEY (role_id) REFERENCES role(role_id)
    );

    INSERT INTO user_role(user_id,role_id) VALUES(1,1);  -- 1号用户对应1号角色
    INSERT INTO user_role(user_id,role_id) VALUES(2,2);
    INSERT INTO user_role(user_id,role_id) VALUES(6,2);
    INSERT INTO user_role(user_id,role_id) VALUES(1,3);
    INSERT INTO user_role(user_id,role_id) VALUES(2,1);
    INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
	User.java   封装用户信息,以及用户对应的多个角色信息
         private id
         private username
         private birthday
         private sex
         private address
         private List<Role> roleList;
    Role.java  封装角色信息,以及当前角色所属的多个用户信息
    	role_id
    	role_name
    	role_detail
    	List<User> userList;

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndRole" resultMap="resultMap1">
      SELECT * FROM `user` u
        LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
        LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
    </select>
    <!-- 封装用户表的数据信息 -->
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
    </resultMap>


    <resultMap id="resultMap1" type="user" extends="userResultMap">
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="roleList" javaType="list" ofType="role">
            <id column="role_id" property="role_id"></id>
            <result column="role_name" property="role_name"></result>
            <result column="role_detail" property="role_detail"></result>
        </collection>
    </resultMap>
</mapper>

延迟加载(懒加载)

什么时候使用什么时候加载(查询)

一对一的延迟加载

# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表  user
    查询主表的所有数据信息
    select * from user;
2.根据关联条件,查询从表  userInfo
    根据主表的id查询对应的详情
    select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置懒加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!--  property: 实体属性名称
            select: 对应的sql语句所在的位置 id
            column: 对应sql语句执行时的条件 -->
        <association property="userInfo" select="findUserInofById" column="id"></association>
    </resultMap>
    <!-- 根据id查询用户详情 -->
    <select id="findUserInofById" resultType="userinfo">
        select * from user_info where id = #{id}
    </select>

一对多的延迟加载

# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分

1.确定主表  user
	查询所有用户信息
	select * from user;
2.根据关联条件,查询从表  orders
	根据用户id查询当前用户拥有的订单
	select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置一对多延迟加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的延迟加载 -->
        <collection property="ordersList" javaType="list" ofType="orders"
         select="findOrdersByUid" column="id"></collection>
    </resultMap>

    <!-- 根据用户id查询当前用户所拥有的订单 -->
    <select id="findOrdersByUid" resultType="orders">
        select * from orders where user_id = #{user_id}
    </select>

三 注解方式实现Mybatis

将相关sql的配置到注解上,mybatis自动解析和加载

Mybatis常用注解:

注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
    作用: 可以代替配置文件

@Insert 添加
	value属性: sql语句
@Options:可选配置(获取主键)
	userGeneratedKeys:开关
	keyProperty		:对象属性
@Update:更新
	Value:sql语句
@Delete : 删除
	Value:sql语句
@Select : 查询
	Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系: 
	@Results:声明映射关系的配置
		Value:接受@Result的数组
			@Result:
				id: true(默认值为false)
           	 	property = "实体中的属性名"
            	column = "查询结果列名"
	@Result:配置映射关系
		Id:(boolean)声明是否为主键配置
		Property:对象中的属性名
		Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多

注解的一对一映射

// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
	// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                column = "id",   // 懒加载需要传递的参数
                property = "userInfo", // 懒加载的结果需要封装到哪个属性上
                javaType = UserInfo.class, // 懒加载返回的结果的数据类型
                one=@One(
                    	// 懒加载时调用的sql语句的位置
                        select = "com.itheima.dao.UserDao.findUserInofById",
                        fetchType=FetchType.LAZY // 懒加载
                )
            )
    })
    List<User> findAll();
    // 根据id查询用户详情
    @Select("select * from user_info where id = #{id}")
    UserInfo findUserInofById(int id);

注解的一对多映射

// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                    column = "id", // 传递给延迟加载方法的参数
                    property = "ordersList",  // 延迟加载结果封装的属性名称
                    javaType = List.class, // 属性的类型
                    many = @Many(
                        // 延迟加载sql语句的位置
                        select = "com.itheima.dao.UserDao.findOrdersByUid",
                        fetchType = FetchType.LAZY // 设置延迟加载
                    )
            )
    })
    List<User> findAll();

    // 根据用户id查询当前用户所拥有的订单信息
    @Select("select * from orders where user_id = #{user_id}")
    List<Orders> findOrdersByUid(int user_id);

Mybatis中的缓存(了解)

缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
    作用: 降低数据库的压力
Mybatis的缓存:
	一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
    二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
		1.在Mybatis的核心配置文件中开启对二级缓存的支持
        	<setting name="cacheEnabled" value="true"/>
        2.需要缓存的实体对象必须实现序列化接口
        3.在sql映射文件中开启缓存支持
        	<!-- 开启对二级缓存的支持 -->
    		<cache/>
            <!-- 查询所有用户信息 -->
            <select id="findUserById" resultType="USer" useCache="true">
                select * from user where id = #{id};
            </select>
        4.sqlSession提交和关闭

总结

Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
		两类配置文件:
				核心配置文件:
						存放连接数据库的数据信息
            1.设置加载的properties配置文件(获取连接数据库的基本信息)
            2.设置别名(给类的全限定名起别名)
            3.设置操作数据库时使用JDBC的事务,和连接池
            4.设置sql映射文件的位置
				sql映射文件:
						存放sql语句
            namespace: 用于区分多个sql映射文件
            id: sql语句的唯一标识.
            <select></select>
            <insert></insert>
            <delete></delete>
            <update></update>
		编写自己的业务代码:
				传统方式:
						在dao层编写业务接口,提供相关方法
						编写接口的实现类,手动调用Mybatis提供的相关API
				动态代理方式:
						在dao层编写业务接口,提供相关方法
    程序启动时:
				程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
        Configuration对象:
						别名配置
            连接数据库的基本信息: url driver username password
            Map<key,value>
              	key: namespace.id
                value: MappedStatement
                  	sql: sql语句
                    parameterType: 请求参数类型
                    resultType: 返回结果类型
                    ...								
API:
		SqlSessionFactoryBuilder:负责解析配置文件
    SqlSessionFactory:  线程安全的对象
				负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
    SqlSession: 不是线程安全的对象
				提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
      	selectList(参数1,参数2);
				selectOne(参数1,参数2);
				insert(参数1,参数2);
				update(参数1,参数2);
				delete(参数1,参数2);
				commit();
				rollback();
				close();
				T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
  	导入jar包
  	导入核心配置文件(log4j配置文件)
  	编写user业务的接口,提供相关方法
  	在user业务对应的sql映射文件中编写sql语句
  			namespace: 接口的全限定名
        id: 接口中的方法名称
------------------------------------------------
核心配置文件:
		 1.设置加载的properties配置文件(获取连接数据库的基本信息)
     2.设置别名(给类的全限定名起别名)
     3.设置操作数据库时使用JDBC的事务,和连接池
     4.设置sql映射文件的位置
Sql映射文件:
		 <select></select>
     <insert></insert>
     <delete></delete>
     <update></update>
     传入参数类型:
				基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        map: map
        list: list
        数组: int[] _int[]
		 获取传入参数的值:
				OGNL表达式:获取传入参数的值
          格式:
							#{} 占位符,preparedStatement对象
              ${} 拼接符,Statement对象
          基本类型和String:
              #{随便写}  ${value}
          pojo对象:
              #{pojo对象中的属性名}
							${pojo对象中的属性名}
          map: map
            	#{map的key}
							${map的key}
          list: list
            	遍历
          数组: int[] _int[]
            	遍历
		 传出参数类型:
      	基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        list<泛型>:
						使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)

回顾

1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
		1.导入jar包
    	log4j日志包
      mysql驱动包
      mybatis的jar包
    2.导入配置文件
      log4j日志包
      mybatis核心配置文件 xml
      sql映射文件
    3.编写代码
      传统方式:
					配置完核心配置文件后
					直接在sql映射文件中编写sql语句
          调用sqlSession的API,指定sql语句,执行方法
      动态代理方式:
					配置完核心配置文件后
					在sql映射文件中编写sql语句
          编写dao层的接口
          调用sqlSession的getMapper方法,生成接口的实现类(代理类),
					在代理类中调用Sqlsession的相关方法完成增删改查
API:
		SqlSessionFactoryBuilder: 解析
      	作用: 解析配置文件(核心配置文件,sql映射文件)
        方法: build(is);
		SqlSessionFactory: 线程安全(内部没有共享的变量)
      	作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
        方法: openSession(boolean);
		SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
				作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
        方法:
						selectList("namespace.id",参数);
						selectOne("namespace.id",参数);
						insert("namespace.id",参数);
						update("namespace.id",参数);
            delete("namespace.id",参数);
						rollback();
						commit();
						close();
						T getMapper(T.class);
								底层使用动态代理,生成接口的实现类,
								在接口的实现类方法中调用以上方法完成增删改查

Mybatis

作用: 对jdbc进行了封装,将sql语句与java代码分离

一 传统方式实现Mybatis

程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)

入门实现

1.导入jar包

2.准备mybatis的配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

sql映射文件-user

<?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: 区分多个sql映射文件
-->
<mapper namespace="user">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="user">
		select *  from user
	</select>

    <!-- select 一条记录 -->
    <select id="queryOne" resultType="user" parameterType="int">
		select *  from user where id = #{id}
	</select>

</mapper>

sql映射文件-product

<?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: 区分多个sql映射文件
-->
<mapper namespace="product">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="product">
		select *  from product
	</select>

</mapper>

启动解析过程

xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
  String url;
	String driver;
	String username;
	String password;
	Map<String,Mapper>
        key:String,存放当前sql的唯一标识
            sql语句标签上id属性的值
            命名空间.id
        value: Mapper,当前的sql语句及返回值对象
        
Mapper.java  一个sql语句对应一个Mapper
  String sql; // 配置文件中的sql语句
	String resultType; // sql执行后返回的数据类型
	String parameterType; // sql执行时需要传入的参数类型

3.编写自己的业务

mybatis提供的相关API方法

Mybatis封装好的方法:
	SqlSession提供操作数据库的方法
		参数1: mapperId = namespace.id; 找到对应的sql语句
    参数2: 执行当前sql需要使用的参数
    selectList("mapperId",参数...);
		selectOne("mapperId",参数...);
		insert("mapperId",参数...);
		update("mapperId",参数...);
		delete("mapperId",参数...);
	在以上方法中封装了JDBC操作
    commit();
		rollback();
		close();
		创建接口的实现类对象(代理类)
		getMapper(Class ...);

user业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
    List<User> findAll() throws IOException;
    User findById(int id);
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

/**
 * 传统方式:
 *      手动调用Mybatis提供的方法,完成增删改查
 */
public class UserMapperImpl implements UserMapper {

    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        MybatisUtils.close(sqlSession);
        return user;
    }

   /* private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        return user;
    }*/

}

product业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
    List<Product> findAll();
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

public class ProductMapperImpl implements ProductMapper {

    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }



    /*private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        sqlSession.close();
        return list;
    }*/
}

Mybatis工具类

package com.itheima.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 {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象(默认手动提交事务)
     * @return
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 根据传递的参数,返回具体的sqlSession对象
     * @param flag
     * @return
     */
    public static SqlSession getSqlSession(boolean flag){
        return sqlSessionFactory.openSession(flag);
    }

    public static void close(SqlSession sqlSession){
        if (sqlSession!=null){
            sqlSession.close();
        }
    }
}

Log4j日志

1.导入jar包
2.导入配置文件 

二 动态代理方式实现Mybatis★

程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行 
约定大于配置:
		框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定: 
		mybatis在定位sql语句时,使用的是  接口的全限定名.方法名称
    	例子: 查找findAll方法调用的sql语句
			com.itheima.dao.UserDao.findAll

代码实现

1.导入jar包

2.编写配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

3.编写我们的逻辑

user接口

package com.itheima.dao;

import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    // 查询所有用户信息
    List<User> findAll();
    // 根据id查询
    User findById(int id);

    // 添加
    int insertUser(User user);
    int insertUser1(User user);
    // 修改
    int updateUser(Map<String,Object> userMap);
     删除
    int deleteUser(int id);
    // 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
    List<User> findUserByMohu(@Param("name") String username);

    /**
     * 将user表中的数据封装到对应的Person中
     * @return
     */
    List<Person> findUserToPerson();

    /**
     * 参数罗列时,必须给参数起别名
     * @param username
     * @param sex
     * TODO: 请求参数有多个时,必须起别名
     * @return
     */
    List<User> findUserByTiaojian(@Param("username") String username,
                                  @Param("sex") String sex);

    /**
     * 动态sql进行修改
     * @return
     */
    int updateUser1(User user);

    /**
     * 请求参数为数组
     * @param ids
     * @return
     */
    List<User> findUserByIds1(int[] ids);
    List<User> findUserByIds2(List<Integer> ids);
}

sql映射文件

<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
    TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
    TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
    <!-- select 查询所有 -->
	<select id="findAll" resultType="user">
		select *  from user
	</select>
	<!--
		select标签: 表示查询,用于描述查询的sql语句
		id: 唯一标识,找到唯一的一条sql语句
		parameterType: 请求参数的类型
		resultType: 返回值类型
			返回值的全限定名(也可以使用别名)
		TODO:获取请求参数: 在sql中获取请求携带的参数值
			OGNL表达式: 获取请求携带的参数值
				格式:
					#{} : 占位符,底层使用PreparedStatement执行sql语句
					${} : 字符串拼接,底层使用Statement执行sql语句
				请求参数类型:
					基本类型或String:
						#{随便写}
						${value}
					pojo实体对象
						#{属性名}
					list
					map
					...
	-->
	<!--<select id="findById" parameterType="int" resultType="user">
		select * from user where id = #{随便写}
	</select>-->
	<select id="findById" parameterType="int" resultType="user">
		select * from user where id = ${value}
	</select>
	<!--
		增删改,默认返回int(影响的行数),此返回值不需要设置
		OGNL: 获取pojo对象中的数据
			#{属性名}
	-->
	<!--
		resultType: 主键类型
		keyColumn: 主键字段名称
		keyProperty: 将查询结果赋给实体对象中的哪个属性
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	-->
	<insert id="insertUser" parameterType="user">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	</insert>
	<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
	</insert>
	<!-- 修改操作:
	 	OGNL表达式: 获取map中的值
	 		#{map的key}
	 -->
	<update id="updateUser" parameterType="map">
		update user set username=#{username},birthday=#{birthday},
		sex=#{sex},address=#{address} where id=#{id}
	</update>

	<!-- 删除 -->
	<delete id="deleteUser" parameterType="int">
		delete from user where id = #{id}
	</delete>

	<!-- 模糊查询 -->
	<select id="findUserByMohu" parameterType="string" resultType="user">
		select * from user where username like concat("%",#{name},"%");
	</select>

	<!-- 别名查询,将查询结果封装到指定对象中 -->
	<!--<select id="findUserToPerson" resultType="Person">
		SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
	</select>-->
	<select id="findUserToPerson" resultMap="userToPersonMap">
		SELECT * FROM user ;
	</select>
	<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
	<resultMap id="userToPersonMap" type="Person">
		<id column="id" property="pid"></id>
		<result column="username" property="pusername"></result>
		<result column="birthday" property="pbirthday"></result>
		<result column="sex" property="psex"></result>
		<result column="address" property="paddress"></result>
	</resultMap>

	<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
	 	select * from user
		select * from user where username like concat('%',#{username},'%')
		select * from user where sex = #{sex}
		select * from user where username like concat('%',#{username},'%') and sex = #{sex}
	 -->
	<select id="findUserByTiaojian" resultType="User">
		select * from user
		<where>
			<if test="username!=null and username!=''">
				and username like concat('%',#{username},'%')
			</if>
			<if test="sex!=null and sex!=''">
				and sex = #{sex}
			</if>
		</where>
	</select>

	<!-- 动态修改 -->
	<update id="updateUser1" parameterType="User">
		update user
		<set>
			<if test="username!=null and username!=''">
				username=#{username},
			</if>
			<if test="birthday!=null and birthday!=''">
				birthday=#{birthday},
			</if>
			<if test="sex!=null and sex!=''">
				sex=#{sex},
			</if>
			<if test="address!=null and address!=''">
				address=#{address},
			</if>
		</set>
		where id=#{id}
	</update>
	<!-- 遍历数组 -->
	<select id="findUserByIds1" parameterType="int[]" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="array" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>

	<!-- 遍历list集合 -->
	<select id="findUserByIds2" parameterType="list" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="list" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>
</mapper>

测试代码

package com.itheima.test;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.*;

public class TestMybatis {

    @Test
    public void test01_FindAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findAll();
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test02_findById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = mapper.findById(5);
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 需求: 添加完毕后,获取最新添加的数据的id值
     */
    @Test
    public void test03_insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("托塔李天王1");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("陈塘关");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }
    @Test
    public void test03_insertUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("嫦娥");
        user.setSex("女");
        user.setBirthday(new Date());
        user.setAddress("月宫");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 修改
     */
    @Test
    public void test04_updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        Map<String, Object> map = new HashMap<>();
        map.put("id",14);
        map.put("username","玉皇大帝");
        map.put("sex","男");
        map.put("birthday",new Date());
        map.put("address","天庭");
        int i = mapper.updateUser(map);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test05_deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int i = mapper.deleteUser(10);
        if(i>0){
            System.out.println("删除成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test06_findUserByMohu(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByMohu("精");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test07_findUserToPerson(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Person> list = mapper.findUserToPerson();
        for (Person person : list) {
            System.out.println(person);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test08_findUserByTiaojian(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByTiaojian("精","女");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test09_updateUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setId(15);
        user.setUsername("嫦娥");
        user.setSex("男");
        user.setAddress("月亮之上");
        int i = mapper.updateUser1(user);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test10_findUserByIds1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int []arr = {1,3,4,5,6};
        List<User> list = mapper.findUserByIds1(arr);
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test11_findUserByIds2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(6);
        List<User> list2 = mapper.findUserByIds2(list);
        for (User user : list2) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }
}

Mybatis核心API

SqlSessionFactoryBuilder: 
	1.解析核心配置文件,以及关联的sql映射文件
	2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
	1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
	1.封装了jdbc操作,增删改查
		selectList("sql语句的id");
		selectOne("...",参数);
		insert("...");
		update("...");
		delete("...");
    2.getMapper
    	生成dao接口的实现类对象(代理类)
    3.事务控制的方法
    	commit();
    	rollback();
    	close();
    sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
	Conn conn;
	// 第一个线程 : 1 张三
	// 第二个线程 : 1 王五
	public int update(String name ,int id ){
		update 表名 set name = ? where 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">
<!--namespace(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user;
    </select>
    <!--
        parameterType: 传入参数类型
            可以传递的参数类型
                基本数据类型 和 String
                pojo对象
                数组
                list
                map
            编写格式:
                以上类型的全限定名
                    基本数据类型 和 String: 直接编写类型名称: int _int
                    pojo对象: com.itheima.pojo.User
                    数组: _int[] int[]
                    list: list
                    map: map
       ognl表达式:
            #{变量名称}: 占位符
                preparedStatement
                pojo: 实体对象的属性名称
            ${变量名称}: 字符串拼接
                Statement: 存在sql注入的风险
    -->
    <insert id="insertUser" parameterType="com.itheima.pojo.User">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
    </insert>
    <!-- 添加完成后,返回新增记录的id值
        useGeneratedKeys: 开启获取主键自增的值 开关
        keyColumn: 数据库主键字段名称
        keyProperty: 实体中属性的名称
     -->
    <insert id="insertUser1" parameterType="com.itheima.pojo.User"
     useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
        <!-- 返回新增记录的id值
             keyColumn: 数据库主键字段名称
             keyProperty: 实体中属性的名称
             resultType: 返回值类型
             order: 添加记录前或后
        -->
       <!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
              select last_insert_id();
        </selectKey>-->
    </insert>

    <!-- 修改
            出入参数: map
                #{map的key}
    -->
    <update id="updateUser" parameterType="map">
        update user
        set
          username=#{username},
          address=#{address},
          sex=#{sex},
          birthday=#{birthday}
        where id = #{id}
    </update>

    <!-- 当传入参数为一个基本类型或String时,
        #{随便写}
        最好见名知意
     -->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

    <!--
        如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
    -->
    <select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
        <!-- select * from user where username like '%${name}%' -->
        select * from user where username like concat('%',#{name},'%');
    </select>

    <!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
    <select id="findUserToPerson" resultMap="findUserToPersonMap">
        select * from user;
    </select>
    <!-- id: 当前resultMap的唯一标识
         type: 将当前的一条查询结果封装的对象类型
     -->
    <resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
        <!-- column: 数据库字段名称
             property: 实体属性名称
         -->
        <id column="id" property="pid"></id>
        <result column="username" property="pusername"></result>
        <result column="birthday" property="pbirthday"></result>
        <result column="sex" property="psex"></result>
        <result column="address" property="paddress"></result>
    </resultMap>
</mapper>

sql映射文件中的相关配置

作用: 主要用于编写sql语句
传入参数: 
	属性: parameterType
返回结果:
	属性: resultType 
	属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
	如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
    基本类型和String: 直接使用对应类型的类型名称即可
      int long
		pojo类型: 编写pojo的全限定名
			全限定名= 包名+类名;
					com.itheima.pojo.User
    	使用别名(别名需要在核心配置文件中进行配置)
		map: map
		list: list
		数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
		在idea中按两次 shift 键
		TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
    格式:
       #{变量名称}: 占位符,preparedStatement
            pojo: 实体对象的属性名称
        		map: 通过map的key获取value的值
        		基本类型或String:
        			  #{随便定义} : 最好见名知意
        		list: 动态sql遍历
        		数组: 动态sql遍历
        ${变量名称}: 字符串拼接,Statement,存在sql注入的风险
        		基本类型或String:
        			${value} : 固定值
     可以在参数列表中使用@Param("别名")给传入的参数起别名

动态sql

<!-- 抽取公共的sql语句 -->
    <sql id="userSql">
        select * from user
    </sql>
    <!-- 多条件查询 -->
    <select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
        <!-- 引用公共的sql语句 -->
        <include refid="userSql"></include>
        <where>
            <if test="username!=null and username!=''">
                and username like concat('%',#{username},'%')
            </if>
            <if test="sex!=null and sex!=''">
                and sex = #{sex}
            </if>
        </where>
    </select>

    <update id="updateUser1" parameterType="com.itheima.pojo.User">
        update user
        <set>
            <if test="username!=null and username!='' ">
                username=#{username},
            </if>
            <if test="address!=null and address!='' ">
                address=#{address},
            </if>
            <if test="sex!=null and sex!='' ">
                sex=#{sex},
            </if>
            <if test="birthday!=null">
                birthday=#{birthday}
            </if>
        </set>
        where id = #{id}
    </update>

    <select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="array" item="id" open="(" close=")" separator=",">
                 #{id}
            </foreach>
        </where>
    </select>

    <select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="list" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

多表查询

一对一

-- 创建用户基本表  User实体
drop table if exists user;
-- 创建用户基本表
create table user (
  id int primary key auto_increment,
  username varchar(20) not null,
  birthday date,
  sex char(1) default '男',
  address varchar(50)
);

insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
    
 -- 用户描述信息表   UserInfo实体
     create table user_info (
       id int primary key,   -- 既是主键又是外键
       height double,  -- 身高厘米
       weight double,   -- 体重公斤
       married tinyint,    -- 是否结婚,1为结婚,0为未婚
       foreign key (id) references user(id)
     );
 -- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
     
-- ========================== java对象
     User.java   封装用户的信息以及对应的描述信息
         private id
         private username
         private birthday
         private sex
         private address
         private UserInfo userInfo; 
     UserInfo.java  封装用户的描述信息,以及对应的用户信息
         id
         height
         weight
         married
         User user;
     多表查询的结果我们可以采用java的实体嵌套

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <select id="findUserAndUserInfo" resultMap="resultMap1">
        SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
        FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对一的映射数据信息 -->
        <association property="userInfo">
            <id column="uiid" property="id"></id>
            <result column="height" property="height"></result>
            <result column="weight" property="weight"></result>
            <result column="married" property="married"></result>
        </association>
    </resultMap>
</mapper>

一对多

-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
-- 创建订单表
    create table orders(
        oid int primary key auto_increment ,   -- 主键
        user_id int not null,   -- 用户id,外键
        number varchar(20),   -- 订单编号
        create_time datetime,  -- 下单时间
        note varchar(100),   -- 备注
        foreign key(user_id) references user(id)   -- 外键约束,关联主表的主键
    );
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');

	User.java   封装用户信息以及对应的订单信息
         private id
         private username
         private birthday
         private sex
         private address
         // 存放当前用户所拥有的多个订单
         private List<Orders> ordersList;
    Orders.java
    	 oid
    	 user_id
    	 number
    	 create_time
    	 note
  	在一对多查询时,在一的一方提供多的一方的实体List集合

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndOrders" resultMap="resultMap1">
        SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="ordersList" javaType="list" ofType="orders">
            <id column="oid" property="oid"></id>
            <result column="user_id" property="user_id"></result>
            <result column="number" property="number"></result>
            <result column="create_time" property="create_time"></result>
            <result column="note" property="note"></result>
        </collection>
    </resultMap>
</mapper>

多对多

	-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
      -- 角色
    CREATE TABLE `role` (
      role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
      role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
      role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
    );
    -- 插入角色记录
    INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
    INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
    INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
    INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
     -- 中间表
    CREATE TABLE user_role (
       user_id INT NOT NULL  COMMENT '用户id',
       role_id INT NOT NULL  COMMENT '角色id',
       PRIMARY KEY (user_id,role_id),  -- 复合主键
       FOREIGN KEY (user_id) REFERENCES `user`(id),   
       FOREIGN KEY (role_id) REFERENCES role(role_id)
    );

    INSERT INTO user_role(user_id,role_id) VALUES(1,1);  -- 1号用户对应1号角色
    INSERT INTO user_role(user_id,role_id) VALUES(2,2);
    INSERT INTO user_role(user_id,role_id) VALUES(6,2);
    INSERT INTO user_role(user_id,role_id) VALUES(1,3);
    INSERT INTO user_role(user_id,role_id) VALUES(2,1);
    INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
	User.java   封装用户信息,以及用户对应的多个角色信息
         private id
         private username
         private birthday
         private sex
         private address
         private List<Role> roleList;
    Role.java  封装角色信息,以及当前角色所属的多个用户信息
    	role_id
    	role_name
    	role_detail
    	List<User> userList;

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndRole" resultMap="resultMap1">
      SELECT * FROM `user` u
        LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
        LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
    </select>
    <!-- 封装用户表的数据信息 -->
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
    </resultMap>


    <resultMap id="resultMap1" type="user" extends="userResultMap">
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="roleList" javaType="list" ofType="role">
            <id column="role_id" property="role_id"></id>
            <result column="role_name" property="role_name"></result>
            <result column="role_detail" property="role_detail"></result>
        </collection>
    </resultMap>
</mapper>

延迟加载(懒加载)

什么时候使用什么时候加载(查询)

一对一的延迟加载

# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表  user
    查询主表的所有数据信息
    select * from user;
2.根据关联条件,查询从表  userInfo
    根据主表的id查询对应的详情
    select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置懒加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!--  property: 实体属性名称
            select: 对应的sql语句所在的位置 id
            column: 对应sql语句执行时的条件 -->
        <association property="userInfo" select="findUserInofById" column="id"></association>
    </resultMap>
    <!-- 根据id查询用户详情 -->
    <select id="findUserInofById" resultType="userinfo">
        select * from user_info where id = #{id}
    </select>

一对多的延迟加载

# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分

1.确定主表  user
	查询所有用户信息
	select * from user;
2.根据关联条件,查询从表  orders
	根据用户id查询当前用户拥有的订单
	select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置一对多延迟加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的延迟加载 -->
        <collection property="ordersList" javaType="list" ofType="orders"
         select="findOrdersByUid" column="id"></collection>
    </resultMap>

    <!-- 根据用户id查询当前用户所拥有的订单 -->
    <select id="findOrdersByUid" resultType="orders">
        select * from orders where user_id = #{user_id}
    </select>

三 注解方式实现Mybatis

将相关sql的配置到注解上,mybatis自动解析和加载

Mybatis常用注解:

注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
    作用: 可以代替配置文件

@Insert 添加
	value属性: sql语句
@Options:可选配置(获取主键)
	userGeneratedKeys:开关
	keyProperty		:对象属性
@Update:更新
	Value:sql语句
@Delete : 删除
	Value:sql语句
@Select : 查询
	Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系: 
	@Results:声明映射关系的配置
		Value:接受@Result的数组
			@Result:
				id: true(默认值为false)
           	 	property = "实体中的属性名"
            	column = "查询结果列名"
	@Result:配置映射关系
		Id:(boolean)声明是否为主键配置
		Property:对象中的属性名
		Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多

注解的一对一映射

// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
	// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                column = "id",   // 懒加载需要传递的参数
                property = "userInfo", // 懒加载的结果需要封装到哪个属性上
                javaType = UserInfo.class, // 懒加载返回的结果的数据类型
                one=@One(
                    	// 懒加载时调用的sql语句的位置
                        select = "com.itheima.dao.UserDao.findUserInofById",
                        fetchType=FetchType.LAZY // 懒加载
                )
            )
    })
    List<User> findAll();
    // 根据id查询用户详情
    @Select("select * from user_info where id = #{id}")
    UserInfo findUserInofById(int id);

注解的一对多映射

// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                    column = "id", // 传递给延迟加载方法的参数
                    property = "ordersList",  // 延迟加载结果封装的属性名称
                    javaType = List.class, // 属性的类型
                    many = @Many(
                        // 延迟加载sql语句的位置
                        select = "com.itheima.dao.UserDao.findOrdersByUid",
                        fetchType = FetchType.LAZY // 设置延迟加载
                    )
            )
    })
    List<User> findAll();

    // 根据用户id查询当前用户所拥有的订单信息
    @Select("select * from orders where user_id = #{user_id}")
    List<Orders> findOrdersByUid(int user_id);

Mybatis中的缓存(了解)

缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
    作用: 降低数据库的压力
Mybatis的缓存:
	一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
    二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
		1.在Mybatis的核心配置文件中开启对二级缓存的支持
        	<setting name="cacheEnabled" value="true"/>
        2.需要缓存的实体对象必须实现序列化接口
        3.在sql映射文件中开启缓存支持
        	<!-- 开启对二级缓存的支持 -->
    		<cache/>
            <!-- 查询所有用户信息 -->
            <select id="findUserById" resultType="USer" useCache="true">
                select * from user where id = #{id};
            </select>
        4.sqlSession提交和关闭

总结

Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
		两类配置文件:
				核心配置文件:
						存放连接数据库的数据信息
            1.设置加载的properties配置文件(获取连接数据库的基本信息)
            2.设置别名(给类的全限定名起别名)
            3.设置操作数据库时使用JDBC的事务,和连接池
            4.设置sql映射文件的位置
				sql映射文件:
						存放sql语句
            namespace: 用于区分多个sql映射文件
            id: sql语句的唯一标识.
            <select></select>
            <insert></insert>
            <delete></delete>
            <update></update>
		编写自己的业务代码:
				传统方式:
						在dao层编写业务接口,提供相关方法
						编写接口的实现类,手动调用Mybatis提供的相关API
				动态代理方式:
						在dao层编写业务接口,提供相关方法
    程序启动时:
				程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
        Configuration对象:
						别名配置
            连接数据库的基本信息: url driver username password
            Map<key,value>
              	key: namespace.id
                value: MappedStatement
                  	sql: sql语句
                    parameterType: 请求参数类型
                    resultType: 返回结果类型
                    ...								
API:
		SqlSessionFactoryBuilder:负责解析配置文件
    SqlSessionFactory:  线程安全的对象
				负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
    SqlSession: 不是线程安全的对象
				提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
      	selectList(参数1,参数2);
				selectOne(参数1,参数2);
				insert(参数1,参数2);
				update(参数1,参数2);
				delete(参数1,参数2);
				commit();
				rollback();
				close();
				T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
  	导入jar包
  	导入核心配置文件(log4j配置文件)
  	编写user业务的接口,提供相关方法
  	在user业务对应的sql映射文件中编写sql语句
  			namespace: 接口的全限定名
        id: 接口中的方法名称
------------------------------------------------
核心配置文件:
		 1.设置加载的properties配置文件(获取连接数据库的基本信息)
     2.设置别名(给类的全限定名起别名)
     3.设置操作数据库时使用JDBC的事务,和连接池
     4.设置sql映射文件的位置
Sql映射文件:
		 <select></select>
     <insert></insert>
     <delete></delete>
     <update></update>
     传入参数类型:
				基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        map: map
        list: list
        数组: int[] _int[]
		 获取传入参数的值:
				OGNL表达式:获取传入参数的值
          格式:
							#{} 占位符,preparedStatement对象
              ${} 拼接符,Statement对象
          基本类型和String:
              #{随便写}  ${value}
          pojo对象:
              #{pojo对象中的属性名}
							${pojo对象中的属性名}
          map: map
            	#{map的key}
							${map的key}
          list: list
            	遍历
          数组: int[] _int[]
            	遍历
		 传出参数类型:
      	基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        list<泛型>:
						使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)

回顾

1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
		1.导入jar包
    	log4j日志包
      mysql驱动包
      mybatis的jar包
    2.导入配置文件
      log4j日志包
      mybatis核心配置文件 xml
      sql映射文件
    3.编写代码
      传统方式:
					配置完核心配置文件后
					直接在sql映射文件中编写sql语句
          调用sqlSession的API,指定sql语句,执行方法
      动态代理方式:
					配置完核心配置文件后
					在sql映射文件中编写sql语句
          编写dao层的接口
          调用sqlSession的getMapper方法,生成接口的实现类(代理类),
					在代理类中调用Sqlsession的相关方法完成增删改查
API:
		SqlSessionFactoryBuilder: 解析
      	作用: 解析配置文件(核心配置文件,sql映射文件)
        方法: build(is);
		SqlSessionFactory: 线程安全(内部没有共享的变量)
      	作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
        方法: openSession(boolean);
		SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
				作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
        方法:
						selectList("namespace.id",参数);
						selectOne("namespace.id",参数);
						insert("namespace.id",参数);
						update("namespace.id",参数);
            delete("namespace.id",参数);
						rollback();
						commit();
						close();
						T getMapper(T.class);
								底层使用动态代理,生成接口的实现类,
								在接口的实现类方法中调用以上方法完成增删改查

Mybatis

作用: 对jdbc进行了封装,将sql语句与java代码分离

一 传统方式实现Mybatis

程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)

入门实现

1.导入jar包

2.准备mybatis的配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

sql映射文件-user

<?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: 区分多个sql映射文件
-->
<mapper namespace="user">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="user">
		select *  from user
	</select>

    <!-- select 一条记录 -->
    <select id="queryOne" resultType="user" parameterType="int">
		select *  from user where id = #{id}
	</select>

</mapper>

sql映射文件-product

<?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: 区分多个sql映射文件
-->
<mapper namespace="product">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="product">
		select *  from product
	</select>

</mapper>

启动解析过程

xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
  String url;
	String driver;
	String username;
	String password;
	Map<String,Mapper>
        key:String,存放当前sql的唯一标识
            sql语句标签上id属性的值
            命名空间.id
        value: Mapper,当前的sql语句及返回值对象
        
Mapper.java  一个sql语句对应一个Mapper
  String sql; // 配置文件中的sql语句
	String resultType; // sql执行后返回的数据类型
	String parameterType; // sql执行时需要传入的参数类型

3.编写自己的业务

mybatis提供的相关API方法

Mybatis封装好的方法:
	SqlSession提供操作数据库的方法
		参数1: mapperId = namespace.id; 找到对应的sql语句
    参数2: 执行当前sql需要使用的参数
    selectList("mapperId",参数...);
		selectOne("mapperId",参数...);
		insert("mapperId",参数...);
		update("mapperId",参数...);
		delete("mapperId",参数...);
	在以上方法中封装了JDBC操作
    commit();
		rollback();
		close();
		创建接口的实现类对象(代理类)
		getMapper(Class ...);

user业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
    List<User> findAll() throws IOException;
    User findById(int id);
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

/**
 * 传统方式:
 *      手动调用Mybatis提供的方法,完成增删改查
 */
public class UserMapperImpl implements UserMapper {

    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        MybatisUtils.close(sqlSession);
        return user;
    }

   /* private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        return user;
    }*/

}

product业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
    List<Product> findAll();
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

public class ProductMapperImpl implements ProductMapper {

    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }



    /*private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        sqlSession.close();
        return list;
    }*/
}

Mybatis工具类

package com.itheima.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 {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象(默认手动提交事务)
     * @return
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 根据传递的参数,返回具体的sqlSession对象
     * @param flag
     * @return
     */
    public static SqlSession getSqlSession(boolean flag){
        return sqlSessionFactory.openSession(flag);
    }

    public static void close(SqlSession sqlSession){
        if (sqlSession!=null){
            sqlSession.close();
        }
    }
}

Log4j日志

1.导入jar包
2.导入配置文件 

二 动态代理方式实现Mybatis★

程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行 
约定大于配置:
		框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定: 
		mybatis在定位sql语句时,使用的是  接口的全限定名.方法名称
    	例子: 查找findAll方法调用的sql语句
			com.itheima.dao.UserDao.findAll

代码实现

1.导入jar包

2.编写配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

3.编写我们的逻辑

user接口

package com.itheima.dao;

import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    // 查询所有用户信息
    List<User> findAll();
    // 根据id查询
    User findById(int id);

    // 添加
    int insertUser(User user);
    int insertUser1(User user);
    // 修改
    int updateUser(Map<String,Object> userMap);
     删除
    int deleteUser(int id);
    // 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
    List<User> findUserByMohu(@Param("name") String username);

    /**
     * 将user表中的数据封装到对应的Person中
     * @return
     */
    List<Person> findUserToPerson();

    /**
     * 参数罗列时,必须给参数起别名
     * @param username
     * @param sex
     * TODO: 请求参数有多个时,必须起别名
     * @return
     */
    List<User> findUserByTiaojian(@Param("username") String username,
                                  @Param("sex") String sex);

    /**
     * 动态sql进行修改
     * @return
     */
    int updateUser1(User user);

    /**
     * 请求参数为数组
     * @param ids
     * @return
     */
    List<User> findUserByIds1(int[] ids);
    List<User> findUserByIds2(List<Integer> ids);
}

sql映射文件

<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
    TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
    TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
    <!-- select 查询所有 -->
	<select id="findAll" resultType="user">
		select *  from user
	</select>
	<!--
		select标签: 表示查询,用于描述查询的sql语句
		id: 唯一标识,找到唯一的一条sql语句
		parameterType: 请求参数的类型
		resultType: 返回值类型
			返回值的全限定名(也可以使用别名)
		TODO:获取请求参数: 在sql中获取请求携带的参数值
			OGNL表达式: 获取请求携带的参数值
				格式:
					#{} : 占位符,底层使用PreparedStatement执行sql语句
					${} : 字符串拼接,底层使用Statement执行sql语句
				请求参数类型:
					基本类型或String:
						#{随便写}
						${value}
					pojo实体对象
						#{属性名}
					list
					map
					...
	-->
	<!--<select id="findById" parameterType="int" resultType="user">
		select * from user where id = #{随便写}
	</select>-->
	<select id="findById" parameterType="int" resultType="user">
		select * from user where id = ${value}
	</select>
	<!--
		增删改,默认返回int(影响的行数),此返回值不需要设置
		OGNL: 获取pojo对象中的数据
			#{属性名}
	-->
	<!--
		resultType: 主键类型
		keyColumn: 主键字段名称
		keyProperty: 将查询结果赋给实体对象中的哪个属性
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	-->
	<insert id="insertUser" parameterType="user">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	</insert>
	<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
	</insert>
	<!-- 修改操作:
	 	OGNL表达式: 获取map中的值
	 		#{map的key}
	 -->
	<update id="updateUser" parameterType="map">
		update user set username=#{username},birthday=#{birthday},
		sex=#{sex},address=#{address} where id=#{id}
	</update>

	<!-- 删除 -->
	<delete id="deleteUser" parameterType="int">
		delete from user where id = #{id}
	</delete>

	<!-- 模糊查询 -->
	<select id="findUserByMohu" parameterType="string" resultType="user">
		select * from user where username like concat("%",#{name},"%");
	</select>

	<!-- 别名查询,将查询结果封装到指定对象中 -->
	<!--<select id="findUserToPerson" resultType="Person">
		SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
	</select>-->
	<select id="findUserToPerson" resultMap="userToPersonMap">
		SELECT * FROM user ;
	</select>
	<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
	<resultMap id="userToPersonMap" type="Person">
		<id column="id" property="pid"></id>
		<result column="username" property="pusername"></result>
		<result column="birthday" property="pbirthday"></result>
		<result column="sex" property="psex"></result>
		<result column="address" property="paddress"></result>
	</resultMap>

	<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
	 	select * from user
		select * from user where username like concat('%',#{username},'%')
		select * from user where sex = #{sex}
		select * from user where username like concat('%',#{username},'%') and sex = #{sex}
	 -->
	<select id="findUserByTiaojian" resultType="User">
		select * from user
		<where>
			<if test="username!=null and username!=''">
				and username like concat('%',#{username},'%')
			</if>
			<if test="sex!=null and sex!=''">
				and sex = #{sex}
			</if>
		</where>
	</select>

	<!-- 动态修改 -->
	<update id="updateUser1" parameterType="User">
		update user
		<set>
			<if test="username!=null and username!=''">
				username=#{username},
			</if>
			<if test="birthday!=null and birthday!=''">
				birthday=#{birthday},
			</if>
			<if test="sex!=null and sex!=''">
				sex=#{sex},
			</if>
			<if test="address!=null and address!=''">
				address=#{address},
			</if>
		</set>
		where id=#{id}
	</update>
	<!-- 遍历数组 -->
	<select id="findUserByIds1" parameterType="int[]" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="array" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>

	<!-- 遍历list集合 -->
	<select id="findUserByIds2" parameterType="list" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="list" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>
</mapper>

测试代码

package com.itheima.test;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.*;

public class TestMybatis {

    @Test
    public void test01_FindAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findAll();
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test02_findById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = mapper.findById(5);
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 需求: 添加完毕后,获取最新添加的数据的id值
     */
    @Test
    public void test03_insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("托塔李天王1");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("陈塘关");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }
    @Test
    public void test03_insertUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("嫦娥");
        user.setSex("女");
        user.setBirthday(new Date());
        user.setAddress("月宫");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 修改
     */
    @Test
    public void test04_updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        Map<String, Object> map = new HashMap<>();
        map.put("id",14);
        map.put("username","玉皇大帝");
        map.put("sex","男");
        map.put("birthday",new Date());
        map.put("address","天庭");
        int i = mapper.updateUser(map);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test05_deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int i = mapper.deleteUser(10);
        if(i>0){
            System.out.println("删除成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test06_findUserByMohu(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByMohu("精");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test07_findUserToPerson(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Person> list = mapper.findUserToPerson();
        for (Person person : list) {
            System.out.println(person);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test08_findUserByTiaojian(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByTiaojian("精","女");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test09_updateUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setId(15);
        user.setUsername("嫦娥");
        user.setSex("男");
        user.setAddress("月亮之上");
        int i = mapper.updateUser1(user);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test10_findUserByIds1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int []arr = {1,3,4,5,6};
        List<User> list = mapper.findUserByIds1(arr);
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test11_findUserByIds2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(6);
        List<User> list2 = mapper.findUserByIds2(list);
        for (User user : list2) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }
}

Mybatis核心API

SqlSessionFactoryBuilder: 
	1.解析核心配置文件,以及关联的sql映射文件
	2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
	1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
	1.封装了jdbc操作,增删改查
		selectList("sql语句的id");
		selectOne("...",参数);
		insert("...");
		update("...");
		delete("...");
    2.getMapper
    	生成dao接口的实现类对象(代理类)
    3.事务控制的方法
    	commit();
    	rollback();
    	close();
    sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
	Conn conn;
	// 第一个线程 : 1 张三
	// 第二个线程 : 1 王五
	public int update(String name ,int id ){
		update 表名 set name = ? where 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">
<!--namespace(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user;
    </select>
    <!--
        parameterType: 传入参数类型
            可以传递的参数类型
                基本数据类型 和 String
                pojo对象
                数组
                list
                map
            编写格式:
                以上类型的全限定名
                    基本数据类型 和 String: 直接编写类型名称: int _int
                    pojo对象: com.itheima.pojo.User
                    数组: _int[] int[]
                    list: list
                    map: map
       ognl表达式:
            #{变量名称}: 占位符
                preparedStatement
                pojo: 实体对象的属性名称
            ${变量名称}: 字符串拼接
                Statement: 存在sql注入的风险
    -->
    <insert id="insertUser" parameterType="com.itheima.pojo.User">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
    </insert>
    <!-- 添加完成后,返回新增记录的id值
        useGeneratedKeys: 开启获取主键自增的值 开关
        keyColumn: 数据库主键字段名称
        keyProperty: 实体中属性的名称
     -->
    <insert id="insertUser1" parameterType="com.itheima.pojo.User"
     useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
        <!-- 返回新增记录的id值
             keyColumn: 数据库主键字段名称
             keyProperty: 实体中属性的名称
             resultType: 返回值类型
             order: 添加记录前或后
        -->
       <!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
              select last_insert_id();
        </selectKey>-->
    </insert>

    <!-- 修改
            出入参数: map
                #{map的key}
    -->
    <update id="updateUser" parameterType="map">
        update user
        set
          username=#{username},
          address=#{address},
          sex=#{sex},
          birthday=#{birthday}
        where id = #{id}
    </update>

    <!-- 当传入参数为一个基本类型或String时,
        #{随便写}
        最好见名知意
     -->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

    <!--
        如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
    -->
    <select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
        <!-- select * from user where username like '%${name}%' -->
        select * from user where username like concat('%',#{name},'%');
    </select>

    <!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
    <select id="findUserToPerson" resultMap="findUserToPersonMap">
        select * from user;
    </select>
    <!-- id: 当前resultMap的唯一标识
         type: 将当前的一条查询结果封装的对象类型
     -->
    <resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
        <!-- column: 数据库字段名称
             property: 实体属性名称
         -->
        <id column="id" property="pid"></id>
        <result column="username" property="pusername"></result>
        <result column="birthday" property="pbirthday"></result>
        <result column="sex" property="psex"></result>
        <result column="address" property="paddress"></result>
    </resultMap>
</mapper>

sql映射文件中的相关配置

作用: 主要用于编写sql语句
传入参数: 
	属性: parameterType
返回结果:
	属性: resultType 
	属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
	如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
    基本类型和String: 直接使用对应类型的类型名称即可
      int long
		pojo类型: 编写pojo的全限定名
			全限定名= 包名+类名;
					com.itheima.pojo.User
    	使用别名(别名需要在核心配置文件中进行配置)
		map: map
		list: list
		数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
		在idea中按两次 shift 键
		TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
    格式:
       #{变量名称}: 占位符,preparedStatement
            pojo: 实体对象的属性名称
        		map: 通过map的key获取value的值
        		基本类型或String:
        			  #{随便定义} : 最好见名知意
        		list: 动态sql遍历
        		数组: 动态sql遍历
        ${变量名称}: 字符串拼接,Statement,存在sql注入的风险
        		基本类型或String:
        			${value} : 固定值
     可以在参数列表中使用@Param("别名")给传入的参数起别名

动态sql

<!-- 抽取公共的sql语句 -->
    <sql id="userSql">
        select * from user
    </sql>
    <!-- 多条件查询 -->
    <select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
        <!-- 引用公共的sql语句 -->
        <include refid="userSql"></include>
        <where>
            <if test="username!=null and username!=''">
                and username like concat('%',#{username},'%')
            </if>
            <if test="sex!=null and sex!=''">
                and sex = #{sex}
            </if>
        </where>
    </select>

    <update id="updateUser1" parameterType="com.itheima.pojo.User">
        update user
        <set>
            <if test="username!=null and username!='' ">
                username=#{username},
            </if>
            <if test="address!=null and address!='' ">
                address=#{address},
            </if>
            <if test="sex!=null and sex!='' ">
                sex=#{sex},
            </if>
            <if test="birthday!=null">
                birthday=#{birthday}
            </if>
        </set>
        where id = #{id}
    </update>

    <select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="array" item="id" open="(" close=")" separator=",">
                 #{id}
            </foreach>
        </where>
    </select>

    <select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="list" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

多表查询

一对一

-- 创建用户基本表  User实体
drop table if exists user;
-- 创建用户基本表
create table user (
  id int primary key auto_increment,
  username varchar(20) not null,
  birthday date,
  sex char(1) default '男',
  address varchar(50)
);

insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
    
 -- 用户描述信息表   UserInfo实体
     create table user_info (
       id int primary key,   -- 既是主键又是外键
       height double,  -- 身高厘米
       weight double,   -- 体重公斤
       married tinyint,    -- 是否结婚,1为结婚,0为未婚
       foreign key (id) references user(id)
     );
 -- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
     
-- ========================== java对象
     User.java   封装用户的信息以及对应的描述信息
         private id
         private username
         private birthday
         private sex
         private address
         private UserInfo userInfo; 
     UserInfo.java  封装用户的描述信息,以及对应的用户信息
         id
         height
         weight
         married
         User user;
     多表查询的结果我们可以采用java的实体嵌套

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <select id="findUserAndUserInfo" resultMap="resultMap1">
        SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
        FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对一的映射数据信息 -->
        <association property="userInfo">
            <id column="uiid" property="id"></id>
            <result column="height" property="height"></result>
            <result column="weight" property="weight"></result>
            <result column="married" property="married"></result>
        </association>
    </resultMap>
</mapper>

一对多

-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
-- 创建订单表
    create table orders(
        oid int primary key auto_increment ,   -- 主键
        user_id int not null,   -- 用户id,外键
        number varchar(20),   -- 订单编号
        create_time datetime,  -- 下单时间
        note varchar(100),   -- 备注
        foreign key(user_id) references user(id)   -- 外键约束,关联主表的主键
    );
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');

	User.java   封装用户信息以及对应的订单信息
         private id
         private username
         private birthday
         private sex
         private address
         // 存放当前用户所拥有的多个订单
         private List<Orders> ordersList;
    Orders.java
    	 oid
    	 user_id
    	 number
    	 create_time
    	 note
  	在一对多查询时,在一的一方提供多的一方的实体List集合

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndOrders" resultMap="resultMap1">
        SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="ordersList" javaType="list" ofType="orders">
            <id column="oid" property="oid"></id>
            <result column="user_id" property="user_id"></result>
            <result column="number" property="number"></result>
            <result column="create_time" property="create_time"></result>
            <result column="note" property="note"></result>
        </collection>
    </resultMap>
</mapper>

多对多

	-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
      -- 角色
    CREATE TABLE `role` (
      role_id INT PRIMARY KEY AUTO_INCREMENT COMMENT '角色id(主键)',
      role_name VARCHAR(32) NOT NULL COMMENT '角色名称',
      role_detail VARCHAR(100) DEFAULT NULL COMMENT '角色描述'
    );
    -- 插入角色记录
    INSERT INTO role(role_name,role_detail) VALUES('校长','全校的管理者');
    INSERT INTO role(role_name,role_detail) VALUES('讲师','传道授业解惑');
    INSERT INTO role(role_name,role_detail) VALUES('班主任','班级的灵魂');
    INSERT INTO role(role_name,role_detail) VALUES('助教','大家的朋友');
     -- 中间表
    CREATE TABLE user_role (
       user_id INT NOT NULL  COMMENT '用户id',
       role_id INT NOT NULL  COMMENT '角色id',
       PRIMARY KEY (user_id,role_id),  -- 复合主键
       FOREIGN KEY (user_id) REFERENCES `user`(id),   
       FOREIGN KEY (role_id) REFERENCES role(role_id)
    );

    INSERT INTO user_role(user_id,role_id) VALUES(1,1);  -- 1号用户对应1号角色
    INSERT INTO user_role(user_id,role_id) VALUES(2,2);
    INSERT INTO user_role(user_id,role_id) VALUES(6,2);
    INSERT INTO user_role(user_id,role_id) VALUES(1,3);
    INSERT INTO user_role(user_id,role_id) VALUES(2,1);
    INSERT INTO user_role(user_id,role_id) VALUES(2,4);
-- ============================= 多对多
	User.java   封装用户信息,以及用户对应的多个角色信息
         private id
         private username
         private birthday
         private sex
         private address
         private List<Role> roleList;
    Role.java  封装角色信息,以及当前角色所属的多个用户信息
    	role_id
    	role_name
    	role_detail
    	List<User> userList;

课堂代码

<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndRole" resultMap="resultMap1">
      SELECT * FROM `user` u
        LEFT JOIN user_role ur ON u.`id` = ur.`user_id`
        LEFT JOIN role r ON ur.`role_id` = r.`role_id`;
    </select>
    <!-- 封装用户表的数据信息 -->
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
    </resultMap>


    <resultMap id="resultMap1" type="user" extends="userResultMap">
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="roleList" javaType="list" ofType="role">
            <id column="role_id" property="role_id"></id>
            <result column="role_name" property="role_name"></result>
            <result column="role_detail" property="role_detail"></result>
        </collection>
    </resultMap>
</mapper>

延迟加载(懒加载)

什么时候使用什么时候加载(查询)

一对一的延迟加载

# 查询所有用户信息以及对应的详细信息
select * from user u left join user_info ui on u.id = ui.id;
拆分
1.确定主表  user
    查询主表的所有数据信息
    select * from user;
2.根据关联条件,查询从表  userInfo
    根据主表的id查询对应的详情
    select * from user_info where id = #{id} ;
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置懒加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!--  property: 实体属性名称
            select: 对应的sql语句所在的位置 id
            column: 对应sql语句执行时的条件 -->
        <association property="userInfo" select="findUserInofById" column="id"></association>
    </resultMap>
    <!-- 根据id查询用户详情 -->
    <select id="findUserInofById" resultType="userinfo">
        select * from user_info where id = #{id}
    </select>

一对多的延迟加载

# 查询所有用户信息以及对应的订单详情
SELECT * FROM `user` u LEFT JOIN orders o ON u.`id`=o.`user_id` ;
拆分

1.确定主表  user
	查询所有用户信息
	select * from user;
2.根据关联条件,查询从表  orders
	根据用户id查询当前用户拥有的订单
	select * from orders where user_id = #{id}
3.需要在Mybatis的核心配置文件中开启对延迟加载的支持
	注意: 注意该标签编写的位置
	<!-- 配置Mybatis的全局属性 -->
    <settings>
        <!-- 开启对懒加载的支持 -->
        <setting name="lazyLoadingEnabled" value="true"/>
    </settings>
4.配置一对多延迟加载
	<!-- 查询所有用户信息 -->
    <select id="findAll" resultMap="userResultMap">
        select * from user;
    </select>
    <resultMap id="userResultMap" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的延迟加载 -->
        <collection property="ordersList" javaType="list" ofType="orders"
         select="findOrdersByUid" column="id"></collection>
    </resultMap>

    <!-- 根据用户id查询当前用户所拥有的订单 -->
    <select id="findOrdersByUid" resultType="orders">
        select * from orders where user_id = #{user_id}
    </select>

三 注解方式实现Mybatis

将相关sql的配置到注解上,mybatis自动解析和加载

Mybatis常用注解:

注释: 对代码的解释说明,是给程序员看的
注解: 对代码的说明,是给jvm虚拟查看
    作用: 可以代替配置文件

@Insert 添加
	value属性: sql语句
@Options:可选配置(获取主键)
	userGeneratedKeys:开关
	keyProperty		:对象属性
@Update:更新
	Value:sql语句
@Delete : 删除
	Value:sql语句
@Select : 查询
	Value:sql语句
@SelectProvider : 拼接动态sql
配置查询结果和实体属性的映射关系: 
	@Results:声明映射关系的配置
		Value:接受@Result的数组
			@Result:
				id: true(默认值为false)
           	 	property = "实体中的属性名"
            	column = "查询结果列名"
	@Result:配置映射关系
		Id:(boolean)声明是否为主键配置
		Property:对象中的属性名
		Column:查询的字段名
----------------------- 单表
查询所有用户信息
条件查询
模糊查询
聚合查询
添加用户信息
修改用户信息
删除用户信息
----------------------- 多表
一对一
一对多

注解的一对一映射

// 注意: 在Mybatis的核心配置文件中开启懒加载
延迟加载(懒加载)
	// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                column = "id",   // 懒加载需要传递的参数
                property = "userInfo", // 懒加载的结果需要封装到哪个属性上
                javaType = UserInfo.class, // 懒加载返回的结果的数据类型
                one=@One(
                    	// 懒加载时调用的sql语句的位置
                        select = "com.itheima.dao.UserDao.findUserInofById",
                        fetchType=FetchType.LAZY // 懒加载
                )
            )
    })
    List<User> findAll();
    // 根据id查询用户详情
    @Select("select * from user_info where id = #{id}")
    UserInfo findUserInofById(int id);

注解的一对多映射

// 查询所有用户信息
    @Select("select * from user ;")
    @Results({
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "username",property = "username"),
            @Result(column = "birthday",property = "birthday"),
            @Result(column = "sex",property = "sex"),
            @Result(column = "address",property = "address"),
            @Result(
                    column = "id", // 传递给延迟加载方法的参数
                    property = "ordersList",  // 延迟加载结果封装的属性名称
                    javaType = List.class, // 属性的类型
                    many = @Many(
                        // 延迟加载sql语句的位置
                        select = "com.itheima.dao.UserDao.findOrdersByUid",
                        fetchType = FetchType.LAZY // 设置延迟加载
                    )
            )
    })
    List<User> findAll();

    // 根据用户id查询当前用户所拥有的订单信息
    @Select("select * from orders where user_id = #{user_id}")
    List<Orders> findOrdersByUid(int user_id);

Mybatis中的缓存(了解)

缓存: 临时存放,将数据临时存放到内存中,当程序停止后,内存就会被释放
    作用: 降低数据库的压力
Mybatis的缓存:
	一级缓存: sqlSession级别的缓存,是Mybatis自带的,关不掉,必须使用
    二级缓存: 可以理解为是SqlSessionFactory基本的缓存,多个SQLSession之间可以共享
		1.在Mybatis的核心配置文件中开启对二级缓存的支持
        	<setting name="cacheEnabled" value="true"/>
        2.需要缓存的实体对象必须实现序列化接口
        3.在sql映射文件中开启缓存支持
        	<!-- 开启对二级缓存的支持 -->
    		<cache/>
            <!-- 查询所有用户信息 -->
            <select id="findUserById" resultType="USer" useCache="true">
                select * from user where id = #{id};
            </select>
        4.sqlSession提交和关闭

总结

Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
Mybatis结构:
		两类配置文件:
				核心配置文件:
						存放连接数据库的数据信息
            1.设置加载的properties配置文件(获取连接数据库的基本信息)
            2.设置别名(给类的全限定名起别名)
            3.设置操作数据库时使用JDBC的事务,和连接池
            4.设置sql映射文件的位置
				sql映射文件:
						存放sql语句
            namespace: 用于区分多个sql映射文件
            id: sql语句的唯一标识.
            <select></select>
            <insert></insert>
            <delete></delete>
            <update></update>
		编写自己的业务代码:
				传统方式:
						在dao层编写业务接口,提供相关方法
						编写接口的实现类,手动调用Mybatis提供的相关API
				动态代理方式:
						在dao层编写业务接口,提供相关方法
    程序启动时:
				程序启动时,优先解析所有的配置文件,将解析到的数据存放到Configuration对象中
        Configuration对象:
						别名配置
            连接数据库的基本信息: url driver username password
            Map<key,value>
              	key: namespace.id
                value: MappedStatement
                  	sql: sql语句
                    parameterType: 请求参数类型
                    resultType: 返回结果类型
                    ...								
API:
		SqlSessionFactoryBuilder:负责解析配置文件
    SqlSessionFactory:  线程安全的对象
				负责创建SqlSession对象并将解析到的Configuration传递给SqlSession
    SqlSession: 不是线程安全的对象
				提供了操作数据库的相关方法,在相关方法中封装了JDBC操作完成增删改查
      	selectList(参数1,参数2);
				selectOne(参数1,参数2);
				insert(参数1,参数2);
				update(参数1,参数2);
				delete(参数1,参数2);
				commit();
				rollback();
				close();
				T getMapper(T.class);
传统方式: 了解
动态代理方式: ★★★
  	导入jar包
  	导入核心配置文件(log4j配置文件)
  	编写user业务的接口,提供相关方法
  	在user业务对应的sql映射文件中编写sql语句
  			namespace: 接口的全限定名
        id: 接口中的方法名称
------------------------------------------------
核心配置文件:
		 1.设置加载的properties配置文件(获取连接数据库的基本信息)
     2.设置别名(给类的全限定名起别名)
     3.设置操作数据库时使用JDBC的事务,和连接池
     4.设置sql映射文件的位置
Sql映射文件:
		 <select></select>
     <insert></insert>
     <delete></delete>
     <update></update>
     传入参数类型:
				基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        map: map
        list: list
        数组: int[] _int[]
		 获取传入参数的值:
				OGNL表达式:获取传入参数的值
          格式:
							#{} 占位符,preparedStatement对象
              ${} 拼接符,Statement对象
          基本类型和String:
              #{随便写}  ${value}
          pojo对象:
              #{pojo对象中的属性名}
							${pojo对象中的属性名}
          map: map
            	#{map的key}
							${map的key}
          list: list
            	遍历
          数组: int[] _int[]
            	遍历
		 传出参数类型:
      	基本类型和String:
						直接写对应类型的名称即可
        pojo对象:
						全限定名
            别名
        list<泛型>:
						使用泛型类型的全限定名或别名(将一条记录封装到哪个对象中)

回顾

1.学会使用(按照步骤实现)
2.描述执行流程(当程序启动时,程序是如何执行的)
3.描述执行原理(执行流程中涉及的相关原理有哪些)
Mybatis框架:
		持久层框架,本质上对JDBC进行的封装.简化JDBC操作.
使用:
		1.导入jar包
    	log4j日志包
      mysql驱动包
      mybatis的jar包
    2.导入配置文件
      log4j日志包
      mybatis核心配置文件 xml
      sql映射文件
    3.编写代码
      传统方式:
					配置完核心配置文件后
					直接在sql映射文件中编写sql语句
          调用sqlSession的API,指定sql语句,执行方法
      动态代理方式:
					配置完核心配置文件后
					在sql映射文件中编写sql语句
          编写dao层的接口
          调用sqlSession的getMapper方法,生成接口的实现类(代理类),
					在代理类中调用Sqlsession的相关方法完成增删改查
API:
		SqlSessionFactoryBuilder: 解析
      	作用: 解析配置文件(核心配置文件,sql映射文件)
        方法: build(is);
		SqlSessionFactory: 线程安全(内部没有共享的变量)
      	作用: 创建SqlSession对象,并将解析到的所有配置传递给SqlSession对象
        方法: openSession(boolean);
		SqlSession: 不是线程安全的对象(每次操作数据库时都需要创建一个新对象)
				作用: 执行对数据库的增删改查,在此接口中封装了增删改查的方法,在增删改查方法中完成对数据库的操作.
        方法:
						selectList("namespace.id",参数);
						selectOne("namespace.id",参数);
						insert("namespace.id",参数);
						update("namespace.id",参数);
            delete("namespace.id",参数);
						rollback();
						commit();
						close();
						T getMapper(T.class);
								底层使用动态代理,生成接口的实现类,
								在接口的实现类方法中调用以上方法完成增删改查

Mybatis

作用: 对jdbc进行了封装,将sql语句与java代码分离

一 传统方式实现Mybatis

程序员手动的指定要指定的sql,及要调用的方法(Mybatis封装好的方法)

入门实现

1.导入jar包

2.准备mybatis的配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

sql映射文件-user

<?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: 区分多个sql映射文件
-->
<mapper namespace="user">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="user">
		select *  from user
	</select>

    <!-- select 一条记录 -->
    <select id="queryOne" resultType="user" parameterType="int">
		select *  from user where id = #{id}
	</select>

</mapper>

sql映射文件-product

<?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: 区分多个sql映射文件
-->
<mapper namespace="product">
    <!-- select 查询所有 -->
	<select id="queryAll" resultType="product">
		select *  from product
	</select>

</mapper>

启动解析过程

xml文件中的配置信息java代码不能直接使用,需要解析后才能使用
程序启动后的第一件事情就是解析核心配置文件(以及核心配置文件中配置的sql映射文件)
Configuration
  String url;
	String driver;
	String username;
	String password;
	Map<String,Mapper>
        key:String,存放当前sql的唯一标识
            sql语句标签上id属性的值
            命名空间.id
        value: Mapper,当前的sql语句及返回值对象
        
Mapper.java  一个sql语句对应一个Mapper
  String sql; // 配置文件中的sql语句
	String resultType; // sql执行后返回的数据类型
	String parameterType; // sql执行时需要传入的参数类型

3.编写自己的业务

mybatis提供的相关API方法

Mybatis封装好的方法:
	SqlSession提供操作数据库的方法
		参数1: mapperId = namespace.id; 找到对应的sql语句
    参数2: 执行当前sql需要使用的参数
    selectList("mapperId",参数...);
		selectOne("mapperId",参数...);
		insert("mapperId",参数...);
		update("mapperId",参数...);
		delete("mapperId",参数...);
	在以上方法中封装了JDBC操作
    commit();
		rollback();
		close();
		创建接口的实现类对象(代理类)
		getMapper(Class ...);

user业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.User;
import java.io.IOException;
import java.util.List;
public interface UserMapper {
    List<User> findAll() throws IOException;
    User findById(int id);
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

/**
 * 传统方式:
 *      手动调用Mybatis提供的方法,完成增删改查
 */
public class UserMapperImpl implements UserMapper {

    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        MybatisUtils.close(sqlSession);
        return user;
    }

   /* private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<User> findAll() throws IOException {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> list = sqlSession.selectList("user.queryAll");
        return list;
    }

    @Override
    public User findById(int id) {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("user.queryOne", id);
        return user;
    }*/

}

product业务

接口代码

package com.itheima.dao;
import com.itheima.pojo.Product;
import java.util.List;
public interface ProductMapper {
    List<Product> findAll();
}

实现类代码

package com.itheima.dao.impl;

import com.itheima.dao.ProductMapper;
import com.itheima.pojo.Product;
import com.itheima.utils.MybatisUtils;
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;
import java.util.List;

public class ProductMapperImpl implements ProductMapper {

    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        MybatisUtils.close(sqlSession);
        return list;
    }



    /*private static SqlSessionFactory sqlSessionFactory ;
    static {
        try {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Override
    public List<Product> findAll() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<Product> list = sqlSession.selectList("product.queryAll");
        sqlSession.close();
        return list;
    }*/
}

Mybatis工具类

package com.itheima.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 {
            InputStream is = Resources.getResourceAsStream("mybatisConfig.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession对象(默认手动提交事务)
     * @return
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }

    /**
     * 根据传递的参数,返回具体的sqlSession对象
     * @param flag
     * @return
     */
    public static SqlSession getSqlSession(boolean flag){
        return sqlSessionFactory.openSession(flag);
    }

    public static void close(SqlSession sqlSession){
        if (sqlSession!=null){
            sqlSession.close();
        }
    }
}

Log4j日志

1.导入jar包
2.导入配置文件 

二 动态代理方式实现Mybatis★

程序员只需要编写配置文件,Mybatis会自动的根据配置信息,找到指定的sql语句并执行 
约定大于配置:
		框架底层做了一些约定,我们在使用框架时必须遵循这种约定,不然的话,框架识别不了
约定: 
		mybatis在定位sql语句时,使用的是  接口的全限定名.方法名称
    	例子: 查找findAll方法调用的sql语句
			com.itheima.dao.UserDao.findAll

代码实现

1.导入jar包

2.编写配置文件

一类: mybatis核心配置文件(sqlMapConfig.xml  mybatisConfig.xml)
    1.环境
    	配置mybatis使用的连接池
    	配置连接数据库的基本信息:
			username password url driver
    2.配置sql映射文件的位置
        
二类: sql映射文件
    作用: 编写sql语句
    <select></select>
    <insert></insert>
    <update></update>
    <delete></delete>

核心配置文件

<?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>
    <!-- 加载指的properties配置文件 -->
    <properties resource="db.properties"></properties>

    <!-- 给类的全限定名起别名 -->
    <typeAliases>
        <!-- 给一个类起别名 -->
        <!--<typeAlias type="com.itheima.pojo.User" alias="user"></typeAlias>-->
        <!-- TODO:最终使用方式,给一个包下的所有类起别名
                别名为包下类的类名称,不区分大小写
         -->
        <package name="com.itheima.pojo"></package>
    </typeAliases>
    <!-- TODO:Mybatis核心配置文件:
            environments: 环境-连接数据库的环境
            mappers: 映射,sql语句 映射文件在哪个位置
     -->
    <environments default="default">
        <!--环境变量-->
        <environment id="default">
            <!--事务管理器:由JDBC管理事务 -->
            <transactionManager type="JDBC"/>
            <!--数据源:
                1. POOLED:使用mybatis创建的连接池
                2. UNPOOLED:不使用连接池,每次自己创建连接
                3. JNDI:由服务器提供连接池的资源,我们通过JNDI指定的名字去访问服务器中资源
             -->
            <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>
        </environment>
    </environments>

    <!-- 加载其他的映射文件 -->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
        <mapper resource="mapper/ProductMapper.xml"></mapper>
    </mappers>
</configuration>

3.编写我们的逻辑

user接口

package com.itheima.dao;

import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    // 查询所有用户信息
    List<User> findAll();
    // 根据id查询
    User findById(int id);

    // 添加
    int insertUser(User user);
    int insertUser1(User user);
    // 修改
    int updateUser(Map<String,Object> userMap);
     删除
    int deleteUser(int id);
    // 给请求参数起别名(如果起了别名,那么在sql中必须通过别名获取参数的值)
    List<User> findUserByMohu(@Param("name") String username);

    /**
     * 将user表中的数据封装到对应的Person中
     * @return
     */
    List<Person> findUserToPerson();

    /**
     * 参数罗列时,必须给参数起别名
     * @param username
     * @param sex
     * TODO: 请求参数有多个时,必须起别名
     * @return
     */
    List<User> findUserByTiaojian(@Param("username") String username,
                                  @Param("sex") String sex);

    /**
     * 动态sql进行修改
     * @return
     */
    int updateUser1(User user);

    /**
     * 请求参数为数组
     * @param ids
     * @return
     */
    List<User> findUserByIds1(int[] ids);
    List<User> findUserByIds2(List<Integer> ids);
}

sql映射文件

<?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">
<!--
TODO:动态代理方式对Sql映射文件的约定:
    TODO:namespace:必须为接口的全限定名(全限定名 = 包名+类名)
    TODO:sql标签上的id属性值必须与接口中方法名称一致
-->
<mapper namespace="com.itheima.dao.UserMapper">
    <!-- select 查询所有 -->
	<select id="findAll" resultType="user">
		select *  from user
	</select>
	<!--
		select标签: 表示查询,用于描述查询的sql语句
		id: 唯一标识,找到唯一的一条sql语句
		parameterType: 请求参数的类型
		resultType: 返回值类型
			返回值的全限定名(也可以使用别名)
		TODO:获取请求参数: 在sql中获取请求携带的参数值
			OGNL表达式: 获取请求携带的参数值
				格式:
					#{} : 占位符,底层使用PreparedStatement执行sql语句
					${} : 字符串拼接,底层使用Statement执行sql语句
				请求参数类型:
					基本类型或String:
						#{随便写}
						${value}
					pojo实体对象
						#{属性名}
					list
					map
					...
	-->
	<!--<select id="findById" parameterType="int" resultType="user">
		select * from user where id = #{随便写}
	</select>-->
	<select id="findById" parameterType="int" resultType="user">
		select * from user where id = ${value}
	</select>
	<!--
		增删改,默认返回int(影响的行数),此返回值不需要设置
		OGNL: 获取pojo对象中的数据
			#{属性名}
	-->
	<!--
		resultType: 主键类型
		keyColumn: 主键字段名称
		keyProperty: 将查询结果赋给实体对象中的哪个属性
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	-->
	<insert id="insertUser" parameterType="user">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
		<selectKey resultType="int" keyColumn="id" keyProperty="id">
			select last_insert_id();
		</selectKey>
	</insert>
	<insert id="insertUser1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
		insert into user values(null,#{username},#{birthday},#{sex},#{address});
	</insert>
	<!-- 修改操作:
	 	OGNL表达式: 获取map中的值
	 		#{map的key}
	 -->
	<update id="updateUser" parameterType="map">
		update user set username=#{username},birthday=#{birthday},
		sex=#{sex},address=#{address} where id=#{id}
	</update>

	<!-- 删除 -->
	<delete id="deleteUser" parameterType="int">
		delete from user where id = #{id}
	</delete>

	<!-- 模糊查询 -->
	<select id="findUserByMohu" parameterType="string" resultType="user">
		select * from user where username like concat("%",#{name},"%");
	</select>

	<!-- 别名查询,将查询结果封装到指定对象中 -->
	<!--<select id="findUserToPerson" resultType="Person">
		SELECT id pid,username pusername,sex psex,birthday pbirthday,address paddress FROM user ;
	</select>-->
	<select id="findUserToPerson" resultMap="userToPersonMap">
		SELECT * FROM user ;
	</select>
	<!-- ORM:对象关系映射,建立查询结果字段与实体属性的对应关系 -->
	<resultMap id="userToPersonMap" type="Person">
		<id column="id" property="pid"></id>
		<result column="username" property="pusername"></result>
		<result column="birthday" property="pbirthday"></result>
		<result column="sex" property="psex"></result>
		<result column="address" property="paddress"></result>
	</resultMap>

	<!-- 如果有多个请求参数,那么请求参数类型不需要编写.但这多个请求参数需要起别名
	 	select * from user
		select * from user where username like concat('%',#{username},'%')
		select * from user where sex = #{sex}
		select * from user where username like concat('%',#{username},'%') and sex = #{sex}
	 -->
	<select id="findUserByTiaojian" resultType="User">
		select * from user
		<where>
			<if test="username!=null and username!=''">
				and username like concat('%',#{username},'%')
			</if>
			<if test="sex!=null and sex!=''">
				and sex = #{sex}
			</if>
		</where>
	</select>

	<!-- 动态修改 -->
	<update id="updateUser1" parameterType="User">
		update user
		<set>
			<if test="username!=null and username!=''">
				username=#{username},
			</if>
			<if test="birthday!=null and birthday!=''">
				birthday=#{birthday},
			</if>
			<if test="sex!=null and sex!=''">
				sex=#{sex},
			</if>
			<if test="address!=null and address!=''">
				address=#{address},
			</if>
		</set>
		where id=#{id}
	</update>
	<!-- 遍历数组 -->
	<select id="findUserByIds1" parameterType="int[]" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="array" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>

	<!-- 遍历list集合 -->
	<select id="findUserByIds2" parameterType="list" resultType="user">
		select * from user
		<where>
			id in
			<foreach collection="list" open="(" close=")" separator="," item="ele">
				#{ele}
			</foreach>
		</where>
	</select>
</mapper>

测试代码

package com.itheima.test;

import com.itheima.dao.UserMapper;
import com.itheima.pojo.Person;
import com.itheima.pojo.User;
import com.itheima.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.*;

public class TestMybatis {

    @Test
    public void test01_FindAll(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findAll();
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test02_findById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = mapper.findById(5);
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 需求: 添加完毕后,获取最新添加的数据的id值
     */
    @Test
    public void test03_insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("托塔李天王1");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("陈塘关");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }
    @Test
    public void test03_insertUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setUsername("嫦娥");
        user.setSex("女");
        user.setBirthday(new Date());
        user.setAddress("月宫");
        int i = mapper.insertUser(user);
        if(i>0){
            System.out.println("添加成功");
        }
        System.out.println(user);
        MybatisUtils.close(sqlSession);
    }

    /**
     * 修改
     */
    @Test
    public void test04_updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        Map<String, Object> map = new HashMap<>();
        map.put("id",14);
        map.put("username","玉皇大帝");
        map.put("sex","男");
        map.put("birthday",new Date());
        map.put("address","天庭");
        int i = mapper.updateUser(map);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test05_deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int i = mapper.deleteUser(10);
        if(i>0){
            System.out.println("删除成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test06_findUserByMohu(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByMohu("精");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test07_findUserToPerson(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Person> list = mapper.findUserToPerson();
        for (Person person : list) {
            System.out.println(person);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test08_findUserByTiaojian(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<User> list = mapper.findUserByTiaojian("精","女");
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test09_updateUser1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        User user = new User();
        user.setId(15);
        user.setUsername("嫦娥");
        user.setSex("男");
        user.setAddress("月亮之上");
        int i = mapper.updateUser1(user);
        if(i>0){
            System.out.println("修改成功");
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test10_findUserByIds1(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        int []arr = {1,3,4,5,6};
        List<User> list = mapper.findUserByIds1(arr);
        for (User user : list) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }

    @Test
    public void test11_findUserByIds2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession(true);
        //获取接口的实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //调用对象中的方法
        List<Integer> list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(6);
        List<User> list2 = mapper.findUserByIds2(list);
        for (User user : list2) {
            System.out.println(user);
        }
        MybatisUtils.close(sqlSession);
    }
}

Mybatis核心API

SqlSessionFactoryBuilder: 
	1.解析核心配置文件,以及关联的sql映射文件
	2.创建SqlSessionFactory对象,并将解析到的configuration对象传递给工厂对象
SqlSessionFactory: 线程安全
	1.创建SqlSession对象,并将解析到的configuration对象传递给sqlSession对象\
SqlSession: 线程不安全 (connection)
	1.封装了jdbc操作,增删改查
		selectList("sql语句的id");
		selectOne("...",参数);
		insert("...");
		update("...");
		delete("...");
    2.getMapper
    	生成dao接口的实现类对象(代理类)
    3.事务控制的方法
    	commit();
    	rollback();
    	close();
    sqlSession默认不会自动提交事务
-------------------------
DefaultSqlSession{
	Conn conn;
	// 第一个线程 : 1 张三
	// 第二个线程 : 1 王五
	public int update(String name ,int id ){
		update 表名 set name = ? where 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">
<!--namespace(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user;
    </select>
    <!--
        parameterType: 传入参数类型
            可以传递的参数类型
                基本数据类型 和 String
                pojo对象
                数组
                list
                map
            编写格式:
                以上类型的全限定名
                    基本数据类型 和 String: 直接编写类型名称: int _int
                    pojo对象: com.itheima.pojo.User
                    数组: _int[] int[]
                    list: list
                    map: map
       ognl表达式:
            #{变量名称}: 占位符
                preparedStatement
                pojo: 实体对象的属性名称
            ${变量名称}: 字符串拼接
                Statement: 存在sql注入的风险
    -->
    <insert id="insertUser" parameterType="com.itheima.pojo.User">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
    </insert>
    <!-- 添加完成后,返回新增记录的id值
        useGeneratedKeys: 开启获取主键自增的值 开关
        keyColumn: 数据库主键字段名称
        keyProperty: 实体中属性的名称
     -->
    <insert id="insertUser1" parameterType="com.itheima.pojo.User"
     useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into user values(null,#{username},#{birthday},#{sex},#{address});
        <!-- 返回新增记录的id值
             keyColumn: 数据库主键字段名称
             keyProperty: 实体中属性的名称
             resultType: 返回值类型
             order: 添加记录前或后
        -->
       <!-- <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
              select last_insert_id();
        </selectKey>-->
    </insert>

    <!-- 修改
            出入参数: map
                #{map的key}
    -->
    <update id="updateUser" parameterType="map">
        update user
        set
          username=#{username},
          address=#{address},
          sex=#{sex},
          birthday=#{birthday}
        where id = #{id}
    </update>

    <!-- 当传入参数为一个基本类型或String时,
        #{随便写}
        最好见名知意
     -->
    <delete id="deleteUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

    <!--
        如果传入一个字符串参数,使用${}拼接sql时,在$的大括号中必须使用value获取数据
    -->
    <select id="findUserByMohu" parameterType="string" resultType="com.itheima.pojo.User">
        <!-- select * from user where username like '%${name}%' -->
        select * from user where username like concat('%',#{name},'%');
    </select>

    <!-- resultMap: 建立查询结果字段与实体属性的对应关系 -->
    <select id="findUserToPerson" resultMap="findUserToPersonMap">
        select * from user;
    </select>
    <!-- id: 当前resultMap的唯一标识
         type: 将当前的一条查询结果封装的对象类型
     -->
    <resultMap id="findUserToPersonMap" type="com.itheima.pojo.Person">
        <!-- column: 数据库字段名称
             property: 实体属性名称
         -->
        <id column="id" property="pid"></id>
        <result column="username" property="pusername"></result>
        <result column="birthday" property="pbirthday"></result>
        <result column="sex" property="psex"></result>
        <result column="address" property="paddress"></result>
    </resultMap>
</mapper>

sql映射文件中的相关配置

作用: 主要用于编写sql语句
传入参数: 
	属性: parameterType
返回结果:
	属性: resultType 
	属性: resultMap, 建立查询结果字段与返回值对象之间的对应关系
	如果返回的是List<对象> 直接写对象的全限定名(将一条记录封装到指定对象中)
---------------
传入传出参数类型:
    基本类型和String: 直接使用对应类型的类型名称即可
      int long
		pojo类型: 编写pojo的全限定名
			全限定名= 包名+类名;
					com.itheima.pojo.User
    	使用别名(别名需要在核心配置文件中进行配置)
		map: map
		list: list
		数组: _int[] int[]
注意: 查看基本类型或String map 数组 list 对应的别名
		在idea中按两次 shift 键
		TypeAliasRegistry类: 在该类中定义了别名
--------------- 获取传入参数的值
OGNL表达式: 从传入的对象中获取数据信息
    格式:
       #{变量名称}: 占位符,preparedStatement
            pojo: 实体对象的属性名称
        		map: 通过map的key获取value的值
        		基本类型或String:
        			  #{随便定义} : 最好见名知意
        		list: 动态sql遍历
        		数组: 动态sql遍历
        ${变量名称}: 字符串拼接,Statement,存在sql注入的风险
        		基本类型或String:
        			${value} : 固定值
     可以在参数列表中使用@Param("别名")给传入的参数起别名

动态sql

<!-- 抽取公共的sql语句 -->
    <sql id="userSql">
        select * from user
    </sql>
    <!-- 多条件查询 -->
    <select id="findUserByTiaojian" resultType="com.itheima.pojo.User">
        <!-- 引用公共的sql语句 -->
        <include refid="userSql"></include>
        <where>
            <if test="username!=null and username!=''">
                and username like concat('%',#{username},'%')
            </if>
            <if test="sex!=null and sex!=''">
                and sex = #{sex}
            </if>
        </where>
    </select>

    <update id="updateUser1" parameterType="com.itheima.pojo.User">
        update user
        <set>
            <if test="username!=null and username!='' ">
                username=#{username},
            </if>
            <if test="address!=null and address!='' ">
                address=#{address},
            </if>
            <if test="sex!=null and sex!='' ">
                sex=#{sex},
            </if>
            <if test="birthday!=null">
                birthday=#{birthday}
            </if>
        </set>
        where id = #{id}
    </update>

    <select id="findUserByIds1" parameterType="int[]" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="array" item="id" open="(" close=")" separator=",">
                 #{id}
            </foreach>
        </where>
    </select>

    <select id="findUserByIds2" parameterType="list" resultType="com.itheima.pojo.User">
        <include refid="userSql"></include>
        <where>
            id in
            <!-- collection: 被遍历的对象类型
                        array: 表示遍历数组
                        list: 表示遍历list集合
                 item: 将遍历到的数组赋值给此变量
                 open: 以什么开头
                 close: 以什么结尾
                 separator: 用什么分割
            -->
            <foreach collection="list" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

多表查询

一对一

-- 创建用户基本表  User实体
drop table if exists user;
-- 创建用户基本表
create table user (
  id int primary key auto_increment,
  username varchar(20) not null,
  birthday date,
  sex char(1) default '男',
  address varchar(50)
);

insert into user values (null, '孙悟空','1980-10-24','男','花果山水帘洞');
insert into user values (null, '白骨精','1992-11-12','女','白虎岭白骨洞');
insert into user values (null, '猪八戒','1983-05-20','男','福临山云栈洞');
insert into user values (null, '玉面狐','1995-03-22','女','积雷山摩云洞');
insert into user values (null, '玉兔精','2010-02-12','女','天竺国皇宫');
insert into user values (null, '豹子精','2008-05-03','男','隐雾山折岳洞');
    
 -- 用户描述信息表   UserInfo实体
     create table user_info (
       id int primary key,   -- 既是主键又是外键
       height double,  -- 身高厘米
       weight double,   -- 体重公斤
       married tinyint,    -- 是否结婚,1为结婚,0为未婚
       foreign key (id) references user(id)
     );
 -- 插入用户扩展信息表
insert into user_info values(1,185,90,1),(2,170,60,0);
     
-- ========================== java对象
     User.java   封装用户的信息以及对应的描述信息
         private id
         private username
         private birthday
         private sex
         private address
         private UserInfo userInfo; 
     UserInfo.java  封装用户的描述信息,以及对应的用户信息
         id
         height
         weight
         married
         User user;
     多表查询的结果我们可以采用java的实体嵌套



<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <select id="findUserAndUserInfo" resultMap="resultMap1">
        SELECT u.*,ui.id uiid,ui.`height`,ui.`weight`,ui.`married`
        FROM USER u LEFT JOIN user_info ui ON u.id = ui.id;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对一的映射数据信息 -->
        <association property="userInfo">
            <id column="uiid" property="id"></id>
            <result column="height" property="height"></result>
            <result column="weight" property="weight"></result>
            <result column="married" property="married"></result>
        </association>
    </resultMap>
</mapper>

一对多

-- 创建用户基本表  User实体
    create table user (
      id int primary key auto_increment,
      username varchar(20) not null,
      birthday date,
      sex char(1) default '男',
      address varchar(50)
    );
-- 创建订单表
    create table orders(
        oid int primary key auto_increment ,   -- 主键
        user_id int not null,   -- 用户id,外键
        number varchar(20),   -- 订单编号
        create_time datetime,  -- 下单时间
        note varchar(100),   -- 备注
        foreign key(user_id) references user(id)   -- 外键约束,关联主表的主键
    );
-- 添加订单数据
INSERT INTO orders VALUES(NULL, 1,'10001001', NOW(), '请提前安装'),(NULL, 1,'10001002', NOW(), '包邮'),(NULL, 1,'10001003', NOW(), '选择红色');
INSERT INTO orders VALUES(NULL, 2,'10001004', NOW(), '购买多件'),(NULL, 2,'10001005', NOW(), '安全带');

	User.java   封装用户信息以及对应的订单信息
         private id
         private username
         private birthday
         private sex
         private address
         // 存放当前用户所拥有的多个订单
         private List<Orders> ordersList;
    Orders.java
    	 oid
    	 user_id
    	 number
    	 create_time
    	 note
  	在一对多查询时,在一的一方提供多的一方的实体List集合



<?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(命名空间):给当前sql映射文件添加一个唯一标识-->
<!--
    约定:
        namespace: 必须为对应的接口的全限定名
        标签上的id: 必须为对应方法的名称
-->
<mapper namespace="com.itheima.dao.UserDao">
    <!-- 查询所有用户信息 -->
    <select id="findAll" resultType="USer">
        select * from user;
    </select>

    <!-- 一对多查询 -->
    <select id="findUserAndOrders" resultMap="resultMap1">
        SELECT * FROM USER u LEFT JOIN orders o ON u.`id` = o.`user_id`;
    </select>
    <resultMap id="resultMap1" type="user">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!-- 配置一对多的映射关系 -->
        <!--
            property: 实体中对应属性的名称
            javaType: 该属性对应的java的类型
            ofType: 该属性对应的泛型类型
        -->
        <collection property="ordersList" javaType="list" ofType="orders">
            <id column="oid" property="oid"></id>
            <result column="user_id" property="user_id"></result>
            <result column="number" property="number"></result>
            <result column="create_time" property="create_time"></result>
            <result column="note" property="note"></result>
        </collection>
    </resultMap>
</mapper>

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值