mybatis

关于mybatis可能用到的技术:
①mybatis ② mybatis-spring ③MyBatis Generator
优秀的分页插件 PageHelper

起步1–之前的mybatis写法

  • 工程目录
    在这里插入图片描述

  • 所用工具eclipse,MySQL,Mybatis版本3.5.6

  • 所用jar包:mybatis自带的jar包,连接数据库需要的jar包,日志包
    在这里插入图片描述

  • 根据官方文档 进行项目的启动
    数据库中表employee的准备
    在这里插入图片描述
    编写实体类,实体类中有get(),set(),toString(),无参,有参构造器的方法
    在这里插入图片描述

  1. 编写mybatis-config.xml的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url" value="jdbc:mysql://localhost:3306/girls" />
				<property name="username" value="root" />
				<property name="password" value="123456" />
			</dataSource>
		</environment>
	</environments>
	<!-- 全局配置,需要映射 sql语句的xml配置文件 -->
	<mappers>
		<mapper resource="EmployeeMapper.xml" />
	</mappers>
</configuration>
  1. log4j.properties的配置文件
log4j.rootLogger=debug, stdout, logfile
 
log4j.logger.com.ibatis=DEBUG
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
 
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
 
log4j.logger.org.springframework=ERROR
log4j.logger.org.compass=ERROR
 
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
 
log4j.appender.logfile=org.apache.log4j.RollingFileAppender
log4j.appender.logfile.File=empi.log
log4j.appender.logfile.MaxFileSize=512KB
log4j.appender.logfile.MaxBackupIndex=3
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
  1. EmployeeMapper.xml的编写
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hyq.EmployeeMapper">
	<!-- id:唯一标识,resultType:返回的结果类型,这里是返回一个Employee实体 -->
	<select id="selectEmp" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,gender,email 
		from employee 
		where id = #{id}
	</select>
</mapper>
  • 4.编写测试类
public static void main(String[] args) throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
		    /**
		    <T> T selectOne(String statement, Object parameter);
		    	statement Unique identifier matching the statement to use.
		    	parameter A parameter object to pass to the statement.
		    */
		    //这里的selectEmp对应的就是EmployeeMapper.xml中的id
			Employee employee = session.selectOne("selectEmp", 1);
			System.out.println(employee);
		}
	}

起步2–接口式编程写法

  • 编写一个接口EmployeeMapper
public interface EmployeeMapper {
	//查询某个员工
	Employee getEmployeeById(int id);
}
  • 修改EmployeeMapper.xml中的namespace和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对应的是接口的全限定类名 -->
<mapper namespace="com.hyq.dao.EmployeeMapper">
	<!-- 这里的id对应的该接口中的方法名称 -->
	<select id="getEmployeeById" resultType="com.hyq.entity.Employee">
<!-- 这里的lastName要和JavaBean(这里是Employee)中字段一致才能查出具体值,要是不一致,查出的值是空值 -->
		select id,last_name lastName,gender,email 
		from employee 
		where id = #{id}
	</select>
</mapper>
  • 测试类用接口来操作Sql statement
public static void main(String[] args) throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);  //EmployeeMapper是接口
			//输出:org.apache.ibatis.binding.MapperProxy@3159c4b8 
			//这是一个代理的对象
			System.out.println(employeeMapper);
			Employee employee =  employeeMapper.getEmployeeById(1);
			System.out.println(employee);
		}
	}

mybatis的配置

properties

properties中有两个标签url 和 resource
url:加载非类路径下的文件,如磁盘中文件
resource属性是按照类路径的写法来写的,因此必须存在于类路径下

  • 编写jdbc.properties的文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/girls
jdbc.username=root
jdbc.password=123456
  • mybatis-config.xml配置文件中需要引入外部配置文件
    在这里插入图片描述
    项目结构
    在这里插入图片描述

settings

mapUnderscoreToCamelCase

是否开启驼峰命名。默认不开启。若开启,则数据库中假如有一个字段a_name,它会将该字段映射为aName,此时你的JavaBean中若有一个字段是aName,映射的aName会和JavaBean的属性aName自动关联起来。防止有时候出现空值。例如:数据库中字段是a_age,在JavaBean中有一个属性值aAge,若没有开启驼峰命名,则查到的值是空值,当然你可以开启驼峰命名或者是 给 该字段起个别名即可。

typeAliases

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写

  • 1.可以为某个Java类起个别名。如:
<typeAliases>
		<!-- 起别名后,在别的地方不用写全类名,默认 Java类 首字母小写即可 -->
		<typeAlias type="com.hyq.entity.Employee" />
	</typeAliases>

在这里插入图片描述

  • 2.当某个JavaBean包下有多个 Javabean时,为每个包起别名 会出现代码冗余,可以通过设置包的形式为每个Java类 起别名
	<typeAliases>
		<package name="com.hyq.entity"/>
	</typeAliases>
  • 3.当 javabean包下有重名的类时,可以通过注解@Alias
    在这里插入图片描述
  • 4.当Java类上存在@Alias注解时,注解生效,别名就是注解值,mybatis-config.xml中的别名配置不起作用
  • 5.mybatis中内置了一些基本数据类型,包装类,日期类,集合类的别名

mappers(这里项目结构发生了变化,这里的项目结构是常用类型,之后的都以此为准)

项目目录结构
在这里插入图片描述

说明:conf和lib目录是自己创建的文件夹,刚开始创建的文件夹和lib文件夹类型一样,这里要让conf文件夹成为资源目录(如下图),在conf下右键–>Build Path --> Use as Source Folder 后,该conf目录形状就变为了和src一样的标志。使用Java代码加载类路径下的配置文件,就不会出现找不到文件的错误。

在这里插入图片描述
该项目结构中的代码,配置还和上文一致,这里不再赘述

Mappers的使用:我们需要告诉 MyBatis 到哪里去找到SQL的映射文件。

  • 1.使用相对于类路径的资源引用
<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="EmployeeMapper.xml" />
</mappers>

在这里插入图片描述

  • 2.完全限定资源定位符(包括 file:/// 形式的 URL)
<!-- 使用完全限定资源定位符(URL) -->
	<mappers>
		<!-- 这里是根据绝对路径来的。注意:这里必须以file:///开头 -->
		<mapper url="file:///E:/CodeMgr/eclipse/mybatis_02_config/conf/EmployeeMapper.xml"/>
	</mappers>

在这里插入图片描述

  • 3.使用映射器接口实现类的完全限定类名
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="com.hyq.mapper.EmployeeMapper"/>
</mappers>

在这里插入图片描述

  • 4.将包内的映射器接口实现全部注册为映射器
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

在这里插入图片描述
对于xml配置文件和XXXMapper.java接口(针对3和4)还有一种操作如下
在这里插入图片描述
在这里插入图片描述
总结:mybatis-config.xml配置文件 标签有顺序,需要按照顺序来编写

实现简单的增删改查

编写employeeMapper.java接口
在这里插入图片描述
编写EmployeeMapper.xml配置文件
在这里插入图片描述
编写测试类

public void test1() throws IOException {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		SqlSession session =  null;
		try {
			session = sqlSessionFactory.openSession();
			EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
			//插入
			Employee e = new Employee(1,"tom",0,"tom1@qq.com");
//			employeeMapper.addEmp(e);
			//修改
//			employeeMapper.updEmp(e);
			employeeMapper.delEmpById(2);
			//提交 ///////////////////
			session.commit();
		}finally {
			session.close();
		}
	}

插入时获取自增主键的 值

useGeneratedKeys:这会令MyBatis使用 JDBCgetGeneratedKeys方法来取出由数据库内部生成的主键
keyPropertyMyBatis会使用 getGeneratedKeys返回值或 insert 语句的 selectKey子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称.In a word:mybatis在得到主键的值后,会把这个值封装给JavaBean的某个变量(keyProperty="?"里对应的是JavaBean变量)

为插入语句加入上述两个标签
在这里插入图片描述
在这里插入图片描述

mybatis接口中参数规则

  • 1.当接口中的参数只有一个时,mybatis不做处理
    在这里插入图片描述
    在这里插入图片描述
    即:取值方式直接用 #{参数名}。而且参数名随便写
  • 2.当接口中的参数有多个时,如果还写#{参数名} 就会报错
    Employee getEmployeeById(int id,String lastName);
    这时候xml配置文件中如果还用#{id} #{lastName}取值,就会出现异常
    原因是: 多个参数时,将参数封装成 一个Map,map中key就是param1,param2…,map中value就是具体值,这时候如果用#{id} #{lastName}当然是找不到的,可以用#{param1} #{param2},或者是#{0},#{1},但是这种可读性比较差,我们有另外一种操作,就是在参数位置加上注解@param()的方式
Employee getEmployeeById(@Param("id") int id,@Param("lastName") String lastName);

这时候就可以在xml的配置文件中用#{id},#{lastName}的方式来取值

	<select id="getEmployeeById" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,gender,email 
		from employee 
		where id = #{id} and #{lastName}
	</select>
  • 3.参数是实体类pojo时,取值直接用#{实体类中变量名}即可
  • 4.参数过多时,可以用Map传参,取值时就用#{map的key来取值}
Map map = new HashMap();
map.put("id",1);
map.put("lastName","tom");
//对于xml的取值,我们可以直接用#{id},#{lastName}来取值
  • 4.对于集合Collection List 数组Array类型的参数,mybatis作另外的处理
    仍然使用Map封装,但是Mapkeycollection/list/array

常用参数处理

Employee getEmployeeById(int id);
//取参:#{id} #{随便写}
Employee getEmployeeById(int id,String lastName);
//取参:#{0} #{1} / #{param1} #{param2}
Employee getEmployeeById(int id,Employee employee);
//取参:#{0} #{param2.lastName} 
Employee getEmployeeById(int id,@param("e") Employee e);
//取参:#{0} #{e.lastName} 
Employee getEmployeeById(List<Integer> ids);
//取出第一个参数:#{list[0]}

#{}和${}的区别

#{}:是以预编译的形式,将参数设置到sql语句中,有校防止预编译
${}: 直接将参数 放在了 SQL语句中,存在sql注入问题
在这里插入图片描述
在这里插入图片描述

返回的结果是List/Map时的处理

返回结果是list

当返回值类型是List时,resultType并不是写java.util.List,而是写元素类型
编写接口中的方法
List<Employee> getEmpList();*
编写xml 的SQL映射

<!-- 如:这里的resultType写的是List<Employee> 中元素Employee的全限定类名 -->
<select id="getEmpList" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,gender,email 
		from employee 
	</select>

编写测试类
在这里插入图片描述
结果:

[Employee [id=1, lastName=tom, gender=0, email=tom1@qq.com], 
 Employee [id=3, lastName=tom, gender=0, email=tom1@qq.com], 
 Employee [id=4, lastName=tom, gender=0, email=tom1@qq.com]
]

返回结果是Map

  • 1.当返回结果是1条记录
    Map<String,Object> getEmpMap(int id);
    xml配置
<!-- 这里的resultMap是map-->
<select id="getEmpMap" resultType="map">
		select id,last_name lastName,gender,email 
		from employee where id=#{id}
	</select>

结果:

{lastName=tom, gender=0, id=1, email=tom1@qq.com}
  • 2.返回结果是多条记录
    在这里插入图片描述
<!-- 这里的resultType是map中value的元素类型-->
<select id="getEmpMap" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,gender,email 
		from employee where last_name like #{lastName}
	</select>

结果

{1=Employee [id=1, lastName=tom, gender=0, email=tom1@qq.com], 
 3=Employee [id=3, lastName=tom, gender=0, email=tom1@qq.com],
 4=Employee [id=4, lastName=tom, gender=0, email=tom1@qq.com]
}

自定义结果集resultMap的使用

association的使用

编写Employee类和Deptment类,存在get/set/toString/无参/有参构造器的方法
在这里插入图片描述
在这里插入图片描述
编写EmployeeMapperPlus接口方法

public interface EmployeeMapperPlus {
	List<Employee> getEmployeeById();
}

编写EmployeeMapperPlus.xml的配置SQL映射
association元素是处理“有一个”类型的关系,如上面的Employee实体类的Deptment属性(一个员工只能从属于一个部门(员工只能“有一个”部门))

	<!-- 方式一:级联映射-->
	<!--resultMap中的id 是唯一标识,在下面select中resultMap使用了-->
	<resultMap type="com.hyq.entity.Employee" id="emp">
		<id column="id" property="id"/>
		<!--column:数据库中字段对应的列property:Java实体类中的属性-->
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="email" property="email"/>
		<result column="id" property="dept.id"/>
		<result column="dept_name" property="dept.deptName"/>
	</resultMap>
	<!--方式二:关联(association)映射-->
	<!--方式一/方式二写哪个都行-->
		<resultMap type="com.hyq.entity.Employee" id="emp">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="email" property="email"/>
		<!--association可以联合Javabean对象,javaType:指定property中dept的对象类型-->
		<!--association中的property对应的Java中的属性-->
		<association property="dept" javaType="com.hyq.entity.Deptment">
			<id column="id" property="id"/>
			<result column="dept_name" property="deptName"/>
		</association>
	</resultMap>
	<!--最好先在数据库中查询一下,看能不能查询成功,确认无误在往xml中写-->
	<select id="getEmployeeById" resultMap="emp">
		<!--e.id:是因为employee表中有id,department表中也有id,要区分一下-->
		select e.id,last_name,gender,email,dept_name
		from employee e,department d
		where e.id = d.id
	</select>

编写mybatis-config.xml的配置,将SQL映射加入到mybatis的配置文件中去

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<!--引入外部jdbc.properties的配置文件-->
	<properties resource="jdbc.properties"></properties>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<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>
	<!-- 全局配置,需要映射 sql语句的xml配置文件 -->
	<mappers>
		<!--配置包扫描-->
		<package name="com.hyq.mapper" />
	</mappers>
</configuration>

编写测试类

	public void test2() throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			EmployeeMapperPlus employeeMapperPlus = session.getMapper(EmployeeMapperPlus.class);
			System.out.println(employeeMapperPlus);
			List<Employee> employee = employeeMapperPlus.getEmployeeById();
			System.out.println(employee);
		}
	}
[Employee [id=1, lastName=tom1, gender=0, email=tom1@qq.com, dept=Deptment [id=1, deptName=a部, employee=null]], 
 Employee [id=2, lastName=tom2, gender=1, email=tom2@qq.com, dept=Deptment [id=2, deptName=b部, employee=null]] ]

collection的使用

collection处理“有多个”类型的关系,如上面的Deptment类中的List< Employee > 表示一个部门可以有多个员工
编写DeptMapper接口中的方法

List<Deptment> getAll();

编写DeptMapper.xml 实现SQL映射

<resultMap type="com.hyq.entity.Deptment" id="dept">
		<id column="id" property="id"/>
		<result column="dept_name" property="deptName"/>
		<!-- 处理一个部门对应多个员工的情况 -->
		<!-- ofType: 用来指定property="employee"中employee(和Deptment中的List< Employee > employee属性名称一致)的Java类型 -->
		<collection property="employee" ofType="com.hyq.entity.Employee">
			<id column="id" property="id"/>
			<result column="last_name" property="lastName"/>
			<result column="gender" property="gender"/>
			<result column="email" property="email"/>
		</collection>
	</resultMap>
	<select id="getAll" resultMap="dept">
		SELECT d.id,dept_name,last_name,gender,email
		FROM department d,employee e
		WHERE d.id = e.dept_id
	</select>

结果

[Deptment [id=1, deptName=a部, employee=[Employee [id=1, lastName=tom1, gender=0, email=tom1@qq.com, dept=null]]], 
 Deptment [id=2, deptName=b部, employee=[Employee [id=2, lastName=tom2, gender=1, email=tom2@qq.com, dept=null]]]]

动态SQL的使用

小案例

编写DynamicSqlMapper接口中的方法

//通过模糊查询
	List<Employee> getEmpBySql(Employee employee);

编写DynamicSqlMapper.xml实现sql映射,注意要将该xml 映射到全局mybatis-config.xml的配置文件中去,具体操作和上面一样

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hyq.mapper.DynamicSqlMapper">

	<select id="getEmpBySql" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,email,gender,dept_id
		from employee
		<where>
			<if test="lastName!=null">
				<!-- MySQL不允许where后使用别名,别名是查询结果才显示的。
				因为根据MySQL中from,select等的执行顺序表明
				在执行where时,别名还不存在 -->
				last_name like #{lastName}
			</if>
			<if test="email!=null">
				and email like #{email}
			</if>
		</where>		
	</select>
</mapper>
<?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 resource="jdbc.properties"></properties>
	<!-- <settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings> -->

	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<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>
	<!-- 全局配置,需要映射 sql语句的xml配置文件 -->
	<mappers>
		<!--通过包扫描的方式,扫描mapper包下所有xml-->
		<package name="com.hyq.mapper" />
	</mappers>
</configuration>

编写测试类

	public void test() throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			DynamicSqlMapper e = session.getMapper(DynamicSqlMapper.class);
			System.out.println(e);
			//第一种测试
			Employee ep = new Employee(1,"%t%",0,"",null);
			//第二种测试
			Employee ep = new Employee(1,"%1%",0,"%qq%",null);
			List<Employee> employees = e.getEmpBySql(ep);
			System.out.println(employees);
		}
	}

输出结果

//1. SQL执行的语句:主要看where执行条件
==> Preparing: select id,last_name lastName,email,gender,dept_id from employee WHERE last_name like ? and email like ?
==> Parameters: %t%(String), (String)
[] 空值
//2. SQL执行的语句
==>  Preparing: select id,last_name lastName,email,gender,dept_id from employee WHERE last_name like ? and email like ?
==> Parameters: %1%(String), %qq%(String)
[Employee [id=1, lastName=tom1, gender=0, email=tom1@qq.com, dept=null]]

choose-when-otherwise /trim的操作看官网即可
mybatis的官网

foreach用法

你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。
①当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。
②当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

  • 1.集合的遍历
    编写DynamicSqlMapper接口中的方法
List<Employee> getEmpBatch(List<Integer> ids);
  • 2.编写DynamicSqlMapper.xml 实现SQL的映射
<select id="getEmpBatch" resultType="com.hyq.entity.Employee">
		select id,last_name lastName,email,gender,dept_id 
		from employee 
		where id in 
			<!-- where id in(1,2,3) -->
			<foreach collection="list" item="id" open="(" close=")" separator=",">
				#{id}
			</foreach>		
	</select>
  • 3.编写测试类
@Test
	public void test1() throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			DynamicSqlMapper e = session.getMapper(DynamicSqlMapper.class);
			System.out.println(e);
			List<Employee> employees = e.getEmpBatch(Arrays.asList(1,2,3));
			System.out.println(employees);
		}
	}

结果

//SQL语句
==>  Preparing: select id,last_name lastName,email,gender,dept_id from employee where id in ( ? , ? , ? )
==> Parameters: 1(Integer), 2(Integer), 3(Integer)
[Employee [id=1, lastName=tom1, gender=0, email=tom1@qq.com, dept=null], Employee [id=2, lastName=tom2, gender=1, email=tom2@qq.com, dept=null], Employee [id=3, lastName=tom3, gender=0, email=tom3@qq.com, dept=null]]
  • 2.批量添加
    编写DynamicSqlMapper接口中的方法
void addBatch(List<Employee> employees);

编写DynamicSqlMapper.xml 映射sql语句

<select id="addBatch">
		insert into employee(last_name,gender,email,dept_id) values
			<!-- (),(),() -->
			<!-- separator=,是加在了foreach里面的语句后面 -->
			<foreach collection="list" item="emp" separator=",">
				(#{emp.lastName},#{emp.gender},#{emp.email},#{emp.dept.id})
			</foreach>
	</select>

编写测试类

	@Test
	public void test1() throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			DynamicSqlMapper e = session.getMapper(DynamicSqlMapper.class);
			System.out.println(e);
			List<Employee> list = new ArrayList<Employee>();
			list.add(new Employee(null,"xiaoming1",0,"xiaoming1@qq.com",new Deptment(1)));
			list.add(new Employee(null,"xiaoming2",1,"xiaoming2@qq.com",new Deptment(2)));
			list.add(new Employee(null,"xiaoming3",0,"xiaoming3@qq.com",new Deptment(1)));
			e.addBatch(list);
		}
	}

查看sql语句:

==>  Preparing: 
insert into employee(last_name,gender,email,dept_id) values (?,?,?,?) , (?,?,?,?) , (?,?,?,?)
==> Parameters: 
xiaoming1(String), 0(Integer), xiaoming1@qq.com(String), 1(Integer), 
xiaoming2(String), 1(Integer), xiaoming2@qq.com(String), 2(Integer), 
xiaoming3(String), 0(Integer), xiaoming3@qq.com(String), 1(Integer)

缓存概念

  • 一级缓存(默认开启状态)
    在同一次会话(一个sqlSession就是一个会话)期间查询到的数据会放在一级缓存中,同一个会话中有第二次相同操作的查询的话,会直接从缓存中拿数据,不在对数据库进行查询。每一个sqlSession都会放在Map中
    一级缓存不起作用的四种情况
    ①sqlSession不同
    ②sqlSession相同,查询条件不同
    ③sqlSession相同,两次查询之间有增删改操作
    ④sqlSession相同,手动清除了一级缓存
  • 二级缓存
    基于xml中的namespace级别的缓存机制,也就是说基于一个xml文件的缓存,一个namespace对应一个二级缓存
    一次会话会放入一级缓存中,只有当这个会话关闭,才会将一级缓存的数据放入二级缓存中去
    步骤:
    ①mybatis-config.xml全局配置中需要开启缓存
    ②在XXXMapper.xml中开启缓存
    ③PoJo有时需要实现序列化接口
    有一个比较成熟的第三方的缓存工具,如redis,ehcache

mybatis原理刨析

框架的结构
在这里插入图片描述
找一个测试类观察观察,先不用管xml,就单纯的看测试类,看看流程怎么走

public static void main(String[] args) throws Exception {
		//根据xml配置文件创建一个sqlSessionFactory对象
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		SqlSessionFactory sqlSessionFactory =
				new SqlSessionFactoryBuilder().build(inputStream);
		//从sqlSessionFactory中获取一个sqlSession
		try (SqlSession session = sqlSessionFactory.openSession()) {
			EmployeeMapper employeeMapper = session.getMapper(EmployeeMapper.class);
			System.out.println(employeeMapper);
			Employee employee =  employeeMapper.getEmployeeById(1);
			System.out.println(employee);
		}
	}

从上面测试类我们能发现:
1.先拿取一个SqlSessionFactory 工厂
2.通过SqlSessionFactory 得到一个SqlSession
3.通过SqlSession.getMapper()加载接口,这里是接口的代理对象
4.代理对象来帮我们执行增删改查方法

mybatis的四大对象
StatementHandler(prepare,parameterize,batch,update,query)
ParameterHandler(getParameterObject,setParameters)
ResultHandler(handleResultSets,handleOutputParameters)
Executor(update,query,flushStatments,commit,rollback,getTransaction,close,isClosed)

程序如何获取SqlSessionFactory

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

	//处理这个完整的语句,最后并把所有值放入mappedStatement
  public void parseStatementNode() {
    String id = context.getStringAttribute("id");
    String databaseId = context.getStringAttribute("databaseId");

    if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
      return;
    }

    String nodeName = context.getNode().getNodeName();
    SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
    boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
    boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);
    boolean useCache = context.getBooleanAttribute("useCache", isSelect);
    boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);

    // Include Fragments before parsing
    XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
    includeParser.applyIncludes(context.getNode());

    String parameterType = context.getStringAttribute("parameterType");
    Class<?> parameterTypeClass = resolveClass(parameterType);

    String lang = context.getStringAttribute("lang");
    LanguageDriver langDriver = getLanguageDriver(lang);

    // Parse selectKey after includes and remove them.
    processSelectKeyNodes(id, parameterTypeClass, langDriver);

    // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
    KeyGenerator keyGenerator;
    String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;
    keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);
    if (configuration.hasKeyGenerator(keyStatementId)) {
      keyGenerator = configuration.getKeyGenerator(keyStatementId);
    } else {
      keyGenerator = context.getBooleanAttribute("useGeneratedKeys",
          configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))
          ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
    }

    SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
    Integer fetchSize = context.getIntAttribute("fetchSize");
    Integer timeout = context.getIntAttribute("timeout");
    String parameterMap = context.getStringAttribute("parameterMap");
    String resultType = context.getStringAttribute("resultType");
    Class<?> resultTypeClass = resolveClass(resultType);
    String resultMap = context.getStringAttribute("resultMap");
    String resultSetType = context.getStringAttribute("resultSetType");
    ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);
    if (resultSetTypeEnum == null) {
      resultSetTypeEnum = configuration.getDefaultResultSetType();
    }
    String keyProperty = context.getStringAttribute("keyProperty");
    String keyColumn = context.getStringAttribute("keyColumn");
    String resultSets = context.getStringAttribute("resultSets");
	//一个增删改查标签对应一个mappedStatment
    builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
        fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
        resultSetTypeEnum, flushCache, useCache, resultOrdered,
        keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
  }

在这里插入图片描述
在这里插入图片描述

程序如何获取SqlSession

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

程序如何得到的代理对象

在这里插入图片描述
configuration已经有了很多数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如何根据代理对象进行增删改查

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值