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已经有了很多数据
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值