3.尚硅谷_MyBatis_HelloWorld.avi
CREATE TABLE `tbl_employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `last_name` varchar(255) DEFAULT NULL, `gender` varchar(1) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
建立与之对应的bean文件
package com.atguigu.mybatis.bean; public class Employee { private Integer id; private String lastName; private String email; private String gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]"; } }
编写的时候最好保证bean对象的属性值和表名的字段一一对应,这里 private String lastName;和表字段last_name不对应我们看后面如何处理了这是一个关键点
导入所需的jar包
mybatis用到了log4j我们需要在src目录下建立一个log4j.xml
我们创建一个source folder文件夹,必须是这个类型的文件夹,该类型下的文件夹和src在同一目录
source folder文件夹是一种特别的文件夹,如果你用面向对象的思想去看待这个source folder,那么他是folder的一个子集,作为子集,肯定是有folder的所有功能,而且还有自己特别的功能,他的特别之处,就是在source folder下面的java文件都会被编译,编译后的文件会被放在我们设置的某个文件夹下面(一般我们设置成WEB-INF/classes)
log4m.xml文件夹的内容如下
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <param name="Encoding" value="UTF-8" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n" /> </layout> </appender> <logger name="java.sql"> <level value="debug" /> </logger> <logger name="org.apache.ibatis"> <level value="info" /> </logger> <root> <level value="debug" /> <appender-ref ref="STDOUT" /> </root> </log4j:configuration>
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/mybatis" /> <property name="username" value="root" /> <property name="password" value="123456" /> </dataSource> </environment> </environments> <!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 --> <mappers> <mapper resource="EmployeeMapper.xml" /> </mappers> </configuration>
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.atguigu.mybatis.dao.EmployeeMapper"> <!-- namespace:名称空间;指定为接口的全类名 id:唯一标识 resultType:返回值类型 #{id}:从传递过来的参数中取出id值 public Employee getEmpById(Integer id); --> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select id,last_name lastName,email,gender from tbl_employee where id = #{id} </select> </mapper>
上面因为bean的属性和数据库表名不一样,如何解决了在编写mysql的时候可以使用别名的方式来解决select id,last_name lastName,email,gender from tbl_employee where id = #{id} 这里起了一个别名,last_name lastName 第一个是bean中的属性值,第二个是数据库的列名
否则会出现问题
EmployeeMapper
package com.atguigu.mybatis.dao;
import com.atguigu.mybatis.bean.Employee;
public interface EmployeeMapper {
public Employee getEmpById(Integer id);
}
MyBatisTest.java
package com.atguigu.mybatis.test; import java.io.IOException; import java.io.InputStream; 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 org.junit.Test; import com.atguigu.mybatis.bean.Employee; import com.atguigu.mybatis.dao.EmployeeMapper; /** * 1、接口式编程 * 原生: Dao ====> DaoImpl * mybatis: Mapper ====> xxMapper.xml * * 2、SqlSession代表和数据库的一次会话;用完必须关闭; * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。 * (将接口和xml进行绑定) * EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class); * 5、两个重要的配置文件: * mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息 * sql映射文件:保存了每一个sql语句的映射信息: * 将sql抽取出来。 * * * @author lfy * */ public class MyBatisTest { public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); } /** * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息 * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。 * 3、将sql映射文件注册在全局配置文件中 * 4、写代码: * 1)、根据全局配置文件得到SqlSessionFactory; * 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查 * 一个sqlSession就是代表和数据库的一次会话,用完关闭 * 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。 * * @throws IOException */ @Test public void test() throws IOException { // 2、获取sqlSession实例,能直接执行已经映射的sql语句 // sql的唯一标识:statement Unique identifier matching the statement to use. // 执行sql要用的参数:parameter A parameter object to pass to the statement. SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { Employee employee = openSession.selectOne( "com.atguigu.mybatis.dao.EmployeeMapper.getEmpById", 1); System.out.println(employee); } finally { openSession.close(); } } @Test public void test01() throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } }
4.尚硅谷_MyBatis_接口式编程.avi
注意几点:
<?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.atguigu.mybatis.dao.EmployeeMapper"> <!-- namespace:名称空间;指定为接口的全类名 id:唯一标识 resultType:返回值类型 #{id}:从传递过来的参数中取出id值 public Employee getEmpById(Integer id); --> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select id,last_name lastName,email,gender from tbl_employee where id = #{id} </select> </mapper>
第一点:namespace="com.atguigu.mybatis.dao.EmployeeMapper">对应的是需要访问的接口的全类名
第二点:<select id="getEmpById"中id的值和接口下的 public Employee getEmpById(Integer id);名字一一对应
在程序中我们就可以采用接口编程了
package com.atguigu.mybatis.test; import java.io.IOException; import java.io.InputStream; 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 org.junit.Test; import com.atguigu.mybatis.bean.Employee; import com.atguigu.mybatis.dao.EmployeeMapper; /** * 1、接口式编程 * 原生: Dao ====> DaoImpl * mybatis: Mapper ====> xxMapper.xml * * 2、SqlSession代表和数据库的一次会话;用完必须关闭; * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。 * (将接口和xml进行绑定) * EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class); * 5、两个重要的配置文件: * mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息 * sql映射文件:保存了每一个sql语句的映射信息: * 将sql抽取出来。 * * * @author lfy * */ public class MyBatisTest { public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); } /** * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息 * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。 * 3、将sql映射文件注册在全局配置文件中 * 4、写代码: * 1)、根据全局配置文件得到SqlSessionFactory; * 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查 * 一个sqlSession就是代表和数据库的一次会话,用完关闭 * 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。 * * @throws IOException */ @Test public void test() throws IOException { // 2、获取sqlSession实例,能直接执行已经映射的sql语句 // sql的唯一标识:statement Unique identifier matching the statement to use. // 执行sql要用的参数:parameter A parameter object to pass to the statement. SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { Employee employee = openSession.selectOne( "com.atguigu.mybatis.dao.EmployeeMapper.getEmpById", 1); System.out.println(employee); } finally { openSession.close(); } } @Test public void test01() throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } }
上面不在使用session的方法去增删改查,而使用getMapper将sql与接口对象进行绑定,获得接口操作的实现类,这样就可以使用接口的实现对象进行增删改查的操作了,接口的实现类是mybatis自己创建出来的,该对象是一个代理对象去实现增删改查操作。
5.尚硅谷_MyBatis_小结(1).avi
SqlSession代表和数据库的一次会话;用完必须关闭,每一次增删改查都是一次会话
SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。所以不能定义成一个类的成员变量,各个方法进行共享,而应该每个方法使用都应用区获得新的对象
* 5、两个重要的配置文件:
* mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息
* sql映射文件:保存了每一个sql语句的映射信息:
* 将sql抽取出来
6.尚硅谷_MyBatis_全局配置文件_引入dtd约束.avi

我们如何在mybatis的全局配置文件中如何能够引入源文件了
在上面的mybatis-config.xml中我们引入了mybatis的约束文件"http://mybatis.org/dtd/mybatis-3-config.dtd">
EmployeeMapper.xml中引入了"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
,我们如何因为该约束文件的源码了,第一找到mybatis的jar包将该jar包解压
找到下面的两个文件

在eclipse中做下面操作
key type必须是URI
key就是对于的http://mybatis.org/dtd/mybatis-3-mapper.dtd
location就是解压对于的文件
引入之后在xml中就能够实现代码的自动提示了
7.尚硅谷_MyBatis_全局配置文件_properties_引入外部配置文件.avi
上面中因为conf是一个source folder文件夹,所以配置文件EmployeeMapper.xml和实体类Employee在同样的包名com.atguigu.mybatis.bean下,并且xml文件以实体类的类命名
dbconfig.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mybatis jdbc.username=root jdbc.password=123456 orcl.driver=oracle.jdbc.OracleDriver orcl.url=jdbc:oracle:thin:@localhost:1521:orcl orcl.username=scott orcl.password=123456
<!--
1、mybatis可以使用properties来引入外部properties配置文件的内容;
resource:引入类路径下的资源
url:引入网络路径或者磁盘路径下的资源
-->
<properties resource="dbconfig.properties"></properties>
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> <!-- 1、mybatis可以使用properties来引入外部properties配置文件的内容; resource:引入类路径下的资源 url:引入网络路径或者磁盘路径下的资源 --> <properties resource="dbconfig.properties"></properties> <!-- 2、settings包含很多重要的设置项 setting:用来设置每一个设置项 name:设置项名 value:设置项取值 --> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- 3、typeAliases:别名处理器:可以为我们的java类型起别名 别名不区分大小写 --> <typeAliases> <!-- 1、typeAlias:为某个java类型起别名 type:指定要起别名的类型全类名;默认别名就是类名小写;employee alias:指定新的别名 --> <!-- <typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> --> <!-- 2、package:为某个包下的所有类批量起别名 name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写),) --> <package name="com.atguigu.mybatis.bean"/> <!-- 3、批量起别名的情况下,使用@Alias注解为某个类型指定新的别名 --> </typeAliases> <!-- 4、environments:环境们,mybatis可以配置多种环境 ,default指定使用某种环境。可以达到快速切换环境。 environment:配置一个具体的环境信息;必须有两个标签;id代表当前环境的唯一标识 transactionManager:事务管理器; type:事务管理器的类型;JDBC(JdbcTransactionFactory)|MANAGED(ManagedTransactionFactory) 自定义事务管理器:实现TransactionFactory接口.type指定为全类名 dataSource:数据源; type:数据源类型;UNPOOLED(UnpooledDataSourceFactory) |POOLED(PooledDataSourceFactory) |JNDI(JndiDataSourceFactory) 自定义数据源:实现DataSourceFactory接口,type是全类名 --> <environments default="dev_mysql"> <environment id="dev_mysql"> <transactionManager type="JDBC"></transactionManager> <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> <environment id="dev_oracle"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${orcl.driver}" /> <property name="url" value="${orcl.url}" /> <property name="username" value="${orcl.username}" /> <property name="password" value="${orcl.password}" /> </dataSource> </environment> </environments> <!-- 5、databaseIdProvider:支持多数据库厂商的; type="DB_VENDOR":VendorDatabaseIdProvider 作用就是得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql; MySQL,Oracle,SQL Server,xxxx --> <databaseIdProvider type="DB_VENDOR"> <!-- 为不同的数据库厂商起别名 --> <property name="MySQL" value="mysql"/> <property name="Oracle" value="oracle"/> <property name="SQL Server" value="sqlserver"/> </databaseIdProvider> <!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 --> <!-- 6、mappers:将sql映射注册到全局配置中 --> <mappers> <!-- mapper:注册一个sql映射 注册配置文件 resource:引用类路径下的sql映射文件 mybatis/mapper/EmployeeMapper.xml url:引用网路路径或者磁盘路径下的sql映射文件 file:///var/mappers/AuthorMapper.xml 注册接口 class:引用(注册)接口, 1、有sql映射文件,映射文件名必须和接口同名,并且放在与接口同一目录下; 2、没有sql映射文件,所有的sql都是利用注解写在接口上; 推荐: 比较重要的,复杂的Dao接口我们来写sql映射文件 不重要,简单的Dao接口为了开发快速可以使用注解; --> <!-- <mapper resource="mybatis/mapper/EmployeeMapper.xml"/> --> <!-- <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/> --> <!-- 批量注册: --> <package name="com.atguigu.mybatis.dao"/> </mappers> </configuration>
注意点:使用properties 标签导入外面的dbconfig.properties文件
<setting name="mapUnderscoreToCamelCase" value="true"/>设置向映射下划线映射成驼峰命名
作用例如数据库的字段是last_name,实体类的字段是private String lastName;,在mybatis执行查询
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where id = #{id}
</select>
会把数据库的last_name的字段转化成lastName达到一一对应,但是在写代码的时候最好数据库的字段和实体类属性一一对应。
typeAliases起别名
resultType="com.atguigu.mybatis.bean.Employee"
我们经常使用到com.atguigu.mybatis.bean.Employee,我们可以为它起一个简单的别名
<!-- 3、typeAliases:别名处理器:可以为我们的java类型起别名
别名不区分大小写
-->
<typeAliases>
<!-- 1、typeAlias:为某个java类型起别名
type:指定要起别名的类型全类名;默认别名就是类名小写;employee
alias:指定新的别名
-->
<!-- <typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> -->
<!-- 2、package:为某个包下的所有类批量起别名
name:指定包名(为当前包以及下面所有的后代包的每一个类都起一个默认别名(类名小写),)
-->
<package name="com.atguigu.mybatis.bean"/>
<!-- 3、批量起别名的情况下,使用@Alias注解为某个类型指定新的别名 -->
</typeAliases>
package com.atguigu.mybatis.bean; import org.apache.ibatis.type.Alias; @Alias("emp") public class Employee { private Integer id; private String lastName; private String email; private String gender; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + "]"; } }
mybatis为java类型起了下面的别名
_typeHandlers
<!--
4、environments:环境们,mybatis可以配置多种环境 ,default指定使用某种环境。可以达到快速切换环境。
environment:配置一个具体的环境信息;必须有两个标签;id代表当前环境的唯一标识
transactionManager:事务管理器;
type:事务管理器的类型;JDBC(JdbcTransactionFactory)|MANAGED(ManagedTransactionFactory)
自定义事务管理器:实现TransactionFactory接口.type指定为全类名
dataSource:数据源;
type:数据源类型;UNPOOLED(UnpooledDataSourceFactory)
|POOLED(PooledDataSourceFactory)
|JNDI(JndiDataSourceFactory)
自定义数据源:实现DataSourceFactory接口,type是全类名
-->
environment标签必须具有transactionManager和dataSource两个属性文件,两个文件都必须有。
databaseIdProvider_多数据库支持,可以执行不同数据库执行不同的sql语句,mybatis依据不同的配置来执行不同的sql语句
在mybatis-config.xml全局配置文件中
<databaseIdProvider type="DB_VENDOR"> <!-- 为不同的数据库厂商起别名 --> <property name="MySQL" value="mysql"/> <property name="Oracle" value="oracle"/> <property name="SQL Server" value="sqlserver"/> </databaseIdProvider>
在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.atguigu.mybatis.dao.EmployeeMapper"> <!-- namespace:名称空间;指定为接口的全类名 id:唯一标识 resultType:返回值类型 #{id}:从传递过来的参数中取出id值 public Employee getEmpById(Integer id); --> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where id = #{id} </select> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql"> select * from tbl_employee where id = #{id} </select> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="oracle"> select EMPLOYEE_ID id,LAST_NAME lastName,EMAIL email from employees where EMPLOYEE_ID=#{id} </select> </mapper>
通过 databaseId来执行不同的sql语句
_mappers_sql
2、没有sql映射文件,所有的sql都是利用注解写在接口上;
EmployeeMapperAnnotation
package com.atguigu.mybatis.dao; import org.apache.ibatis.annotations.Select; import com.atguigu.mybatis.bean.Employee; public interface EmployeeMapperAnnotation { @Select("select * from tbl_employee where id=#{id}") public Employee getEmpById(Integer id); }
然后再全局配置文件夹中进行注解
基于注解的使用
MyBatisTest
package com.atguigu.mybatis.test; import java.io.IOException; import java.io.InputStream; 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 org.junit.Test; import com.atguigu.mybatis.bean.Employee; import com.atguigu.mybatis.dao.EmployeeMapper; import com.atguigu.mybatis.dao.EmployeeMapperAnnotation; /** * 1、接口式编程 * 原生: Dao ====> DaoImpl * mybatis: Mapper ====> xxMapper.xml * * 2、SqlSession代表和数据库的一次会话;用完必须关闭; * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。 * (将接口和xml进行绑定) * EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class); * 5、两个重要的配置文件: * mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息 * sql映射文件:保存了每一个sql语句的映射信息: * 将sql抽取出来。 * * * @author lfy * */ public class MyBatisTest { public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); } /** * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息 * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。 * 3、将sql映射文件注册在全局配置文件中 * 4、写代码: * 1)、根据全局配置文件得到SqlSessionFactory; * 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查 * 一个sqlSession就是代表和数据库的一次会话,用完关闭 * 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。 * * @throws IOException */ @Test public void test() throws IOException { // 2、获取sqlSession实例,能直接执行已经映射的sql语句 // sql的唯一标识:statement Unique identifier matching the statement to use. // 执行sql要用的参数:parameter A parameter object to pass to the statement. SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { Employee employee = openSession.selectOne( "com.atguigu.mybatis.EmployeeMapper.selectEmp", 1); System.out.println(employee); } finally { openSession.close(); } } @Test public void test01() throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } @Test public void test02() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperAnnotation mapper = openSession.getMapper(EmployeeMapperAnnotation.class); Employee empById = mapper.getEmpById(1); System.out.println(empById); }finally{ openSession.close(); } } }
比较最要的sql我们推荐使用xml方式,不重要的sql我们推荐注解方式
<!-- 批量注册: -->
<package name="com.atguigu.mybatis.dao"/>
批量注册的前提是存在xml文件,xml文件必须和bean文件在同一个保包下,并且满足名字命名规则实体Employee对应的xml文件名是EmployeeMapper.xml这样才满足导入配置文件的规则
整个项目的工程代码如下所示
EmployeeMapper接口
package com.atguigu.mybatis.dao; import java.util.List; import java.util.Map; import org.apache.ibatis.annotations.MapKey; import org.apache.ibatis.annotations.Param; import com.atguigu.mybatis.bean.Employee; public interface EmployeeMapper { //多条记录封装一个map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key @MapKey("lastName") public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName); //返回一条记录的map;key就是列名,值就是对应的值 public Map<String, Object> getEmpByIdReturnMap(Integer id); public List<Employee> getEmpsByLastNameLike(String lastName); public Employee getEmpByMap(Map<String, Object> map); public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName); public Employee getEmpById(Integer id); public Long addEmp(Employee employee); public boolean updateEmp(Employee employee); public void deleteEmpById(Integer id); }
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.atguigu.mybatis.dao.EmployeeMapper"> <!-- namespace:名称空间;指定为接口的全类名 id:唯一标识 resultType:返回值类型 #{id}:从传递过来的参数中取出id值 public Employee getEmpById(Integer id); --> <!--public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName); --> <select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where last_name like #{lastName} </select> <!--public Map<String, Object> getEmpByIdReturnMap(Integer id); --> <select id="getEmpByIdReturnMap" resultType="map"> select * from tbl_employee where id=#{id} </select> <!-- public List<Employee> getEmpsByLastNameLike(String lastName); --> <!--resultType:如果返回的是一个集合,要写集合中元素的类型 --> <select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where last_name like #{lastName} </select> <!-- public Employee getEmpByMap(Map<String, Object> map); --> <select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from ${tableName} where id=${id} and last_name=#{lastName} </select> <!-- public Employee getEmpByIdAndLastName(Integer id,String lastName);--> <select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where id = #{id} and last_name=#{lastName} </select> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where id = #{id} </select> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="mysql"> select * from tbl_employee where id = #{id} </select> <select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee" databaseId="oracle"> select EMPLOYEE_ID id,LAST_NAME lastName,EMAIL email from employees where EMPLOYEE_ID=#{id} </select> <!-- public void addEmp(Employee employee); --> <!-- parameterType:参数类型,可以省略, 获取自增主键的值: mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys(); useGeneratedKeys="true";使用自增主键获取主键值策略 keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性 --> <insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id" databaseId="mysql"> insert into tbl_employee(last_name,email,gender) values(#{lastName},#{email},#{gender}) </insert> <!-- 获取非自增主键的值: Oracle不支持自增;Oracle使用序列来模拟自增; 每次插入的数据的主键是从序列中拿到的值;如何获取到这个值; --> <insert id="addEmp" databaseId="oracle"> <!-- keyProperty:查出的主键值封装给javaBean的哪个属性 order="BEFORE":当前sql在插入sql之前运行 AFTER:当前sql在插入sql之后运行 resultType:查出的数据的返回值类型 BEFORE运行顺序: 先运行selectKey查询id的sql;查出id值封装给javaBean的id属性 在运行插入的sql;就可以取出id属性对应的值 AFTER运行顺序: 先运行插入的sql(从序列中取出新值作为id); 再运行selectKey查询id的sql; --> <selectKey keyProperty="id" order="BEFORE" resultType="Integer"> <!-- 编写查询主键的sql语句 --> <!-- BEFORE--> select EMPLOYEES_SEQ.nextval from dual <!-- AFTER: select EMPLOYEES_SEQ.currval from dual --> </selectKey> <!-- 插入时的主键是从序列中拿到的 --> <!-- BEFORE:--> insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->}) <!-- AFTER: insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) values(employees_seq.nextval,#{lastName},#{email}) --> </insert> <!-- public void updateEmp(Employee employee); --> <update id="updateEmp"> update tbl_employee set last_name=#{lastName},email=#{email},gender=#{gender} where id=#{id} </update> <!-- public void deleteEmpById(Integer id); --> <delete id="deleteEmpById"> delete from tbl_employee where id=#{id} </delete> </mapper>
MyBatisTest.java
package com.atguigu.mybatis.test; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; 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 org.junit.Test; import com.atguigu.mybatis.bean.Department; import com.atguigu.mybatis.bean.Employee; import com.atguigu.mybatis.dao.DepartmentMapper; import com.atguigu.mybatis.dao.EmployeeMapper; import com.atguigu.mybatis.dao.EmployeeMapperAnnotation; import com.atguigu.mybatis.dao.EmployeeMapperPlus; /** * 1、接口式编程 * 原生: Dao ====> DaoImpl * mybatis: Mapper ====> xxMapper.xml * * 2、SqlSession代表和数据库的一次会话;用完必须关闭; * 3、SqlSession和connection一样她都是非线程安全。每次使用都应该去获取新的对象。 * 4、mapper接口没有实现类,但是mybatis会为这个接口生成一个代理对象。 * (将接口和xml进行绑定) * EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class); * 5、两个重要的配置文件: * mybatis的全局配置文件:包含数据库连接池信息,事务管理器信息等...系统运行环境信息 * sql映射文件:保存了每一个sql语句的映射信息: * 将sql抽取出来。 * * * @author lfy * */ public class MyBatisTest { public SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); } /** * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息 * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。 * 3、将sql映射文件注册在全局配置文件中 * 4、写代码: * 1)、根据全局配置文件得到SqlSessionFactory; * 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查 * 一个sqlSession就是代表和数据库的一次会话,用完关闭 * 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。 * * @throws IOException */ @Test public void test() throws IOException { // 2、获取sqlSession实例,能直接执行已经映射的sql语句 // sql的唯一标识:statement Unique identifier matching the statement to use. // 执行sql要用的参数:parameter A parameter object to pass to the statement. SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try { Employee employee = openSession.selectOne( "com.atguigu.mybatis.EmployeeMapper.selectEmp", 1); System.out.println(employee); } finally { openSession.close(); } } @Test public void test01() throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Employee employee = mapper.getEmpById(1); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } @Test public void test02() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperAnnotation mapper = openSession.getMapper(EmployeeMapperAnnotation.class); Employee empById = mapper.getEmpById(1); System.out.println(empById); }finally{ openSession.close(); } } /** * 测试增删改 * 1、mybatis允许增删改直接定义以下类型返回值 * Integer、Long、Boolean、void * 2、我们需要手动提交数据 * sqlSessionFactory.openSession();===》手动提交 * sqlSessionFactory.openSession(true);===》自动提交 * @throws IOException */ @Test public void test03() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //1、获取到的SqlSession不会自动提交数据 SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); //测试添加 Employee employee = new Employee(null, "jerry4",null, "1"); mapper.addEmp(employee); System.out.println(employee.getId()); //测试修改 //Employee employee = new Employee(1, "Tom", "jerry@atguigu.com", "0"); //boolean updateEmp = mapper.updateEmp(employee); //System.out.println(updateEmp); //测试删除 //mapper.deleteEmpById(2); //2、手动提交数据 openSession.commit(); }finally{ openSession.close(); } } @Test public void test04() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //1、获取到的SqlSession不会自动提交数据 SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); //Employee employee = mapper.getEmpByIdAndLastName(1, "tom"); Map<String, Object> map = new HashMap<>(); map.put("id", 2); map.put("lastName", "Tom"); map.put("tableName", "tbl_employee"); Employee employee = mapper.getEmpByMap(map); System.out.println(employee); /*List<Employee> like = mapper.getEmpsByLastNameLike("%e%"); for (Employee employee : like) { System.out.println(employee); }*/ /*Map<String, Object> map = mapper.getEmpByIdReturnMap(1); System.out.println(map);*/ /*Map<String, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%r%"); System.out.println(map);*/ }finally{ openSession.close(); } } @Test public void test05() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class); /*Employee empById = mapper.getEmpById(1); System.out.println(empById);*/ /*Employee empAndDept = mapper.getEmpAndDept(1); System.out.println(empAndDept); System.out.println(empAndDept.getDept());*/ Employee employee = mapper.getEmpByIdStep(3); System.out.println(employee); //System.out.println(employee.getDept()); System.out.println(employee.getDept()); }finally{ openSession.close(); } } @Test public void test06() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class); /*Department department = mapper.getDeptByIdPlus(1); System.out.println(department); System.out.println(department.getEmps());*/ Department deptByIdStep = mapper.getDeptByIdStep(1); System.out.println(deptByIdStep.getDepartmentName()); System.out.println(deptByIdStep.getEmps()); }finally{ openSession.close(); } } }
1、mybatis允许增删改直接定义以下类型返回值
* Integer、Long、Boolean、void
public boolean updateEmp(Employee employee);
* sqlSessionFactory.openSession();===》手动提交
* sqlSessionFactory.openSession(true);===》自动提交
17.尚硅谷_MyBatis_映射文件_insert_获取自增主键的值.avi
mybatis添加数据成功之后需要获得自增主键的值,需要在EmployeeMapper.xml中进行配置
<!-- public void addEmp(Employee employee); --> <!-- parameterType:参数类型,可以省略, 获取自增主键的值: mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys(); useGeneratedKeys="true";使用自增主键获取主键值策略 keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性 --> <insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id" databaseId="mysql"> insert into tbl_employee(last_name,email,gender) values(#{lastName},#{email},#{gender}) </insert>
@Test public void test03() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //1、获取到的SqlSession不会自动提交数据 SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); //测试添加 Employee employee = new Employee(null, "jerry4",null, "1"); mapper.addEmp(employee); System.out.println(employee.getId()); //测试修改 //Employee employee = new Employee(1, "Tom", "jerry@atguigu.com", "0"); //boolean updateEmp = mapper.updateEmp(employee); //System.out.println(updateEmp); //测试删除 //mapper.deleteEmpById(2); //2、手动提交数据 openSession.commit(); }finally{ openSession.close(); } }
我们在上面执行添加操作的时候,未添加之前员工的id为null,员工添加到数据库成功之后,id就已经变成了自增主键的值了,需要上面的配置
21.尚硅谷_MyBatis_映射文件_参数处理_POJO&Map&TO.avi
单个参数:mybatis不会做特殊处理,
#{参数名/任意名}:取出参数值。
<delete id="deleteEmpById"> delete from tbl_employee where id=#{id} </delete>
上面代码等价于
<delete id="deleteEmpById"> delete from tbl_employee where id=#{id535335} </delete>
任意名字都可以
对于多个参数
操作:
方法:public Employee getEmpByIdAndLastName(Integer id,String lastName);
取值:#{id},#{lastName}
这样会报错,存在异常
我们可以使用${param1}和${param1}获得前两个参数的值,使用param参数获得值不便于阅读,我们可以按照下面的方式进行指定
使用@Param参数指定名称,就可以按照下面的方式使用了
【命名参数】:明确指定封装参数时map的key;@Param("id")
多个参数会被封装成 一个map,
key:使用@Param注解指定的值
value:参数值
#{指定的key}取出对应的参数值
第一个参数是可以使用${id}或者#{param1},第二个参数必须使用#param{2}来获得
因为多个参数是封装在map对象中,第一个参数只能使用#{param1},#{param2}就是封装的Employee对象,获得对应的属性值就是#{param.lastName}
使用了@Param("e")指定。可以写为#{e.lastName}
如果传递过来的参数本身就是一个map集合,直接使用map的key取值就可以了
传入List集合只能使用小写的list,Array只能是小写的array
24.尚硅谷_MyBatis_映射文件_参数处理_#与$取值区别.avi
第一个参数使用${id}取值,第二个参数使用#{},$直接将值拼接在sql语句的后面会存在sql注入,#预编译使用的是占位符
但是下面这种情况可以使用$
例如一个表示2016_salary 2017_salary这样分表的,上面#{}取值只能放在sql的where字段后面。不能使用在表名上面取值,这个时候可以使用${}取值的方式
还有排序操作也不支持#的方式取值,直接将值拼接在sql语句上
25.尚硅谷_MyBatis_映射文件_参数处理_#取值时指定参数相关规则.avi
#{}获得参数可以安装上面的方式有更多的操作
jdbcType是要重点强调的,oracle数据库使用mybatis插入到oracle数据库不支持插入的字段为null
我们将员工的eamil设置为null,如果插入进oracle数据库中就会报错,默认请求下mybatis会将null字段映射为other字段,但是在oracle中不存在other字段,所以就会报错
但是mysql数据库支持不存在上面的问题,如何解决了,我们可以使用jdbcTYpe进行解决,在oracle环境下不能让null字段映射为other字段,还应该是null字段
使用上面的语句就不会报错了,但是只在当前的sql语句中有效,第二种可以全局进行配置
这样就会解决上面的问题
26.尚硅谷_MyBatis_映射文件_select_返回List.avi
public List<Employee> getEmpsByLastNameLike(String lastName);
查询返回一个List集合,如何处理了,resultType要写list集合中元素的全类名
<!-- public List<Employee> getEmpsByLastNameLike(String lastName); --> <!--resultType:如果返回的是一个集合,要写集合中元素的类型 --> <select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where last_name like #{lastName} </select>
27.尚硅谷_MyBatis_映射文件_select_记录封装map.avi
如果通过id查询,需要返回一个map对象如何处理了,map对象中key为列名id,key为对应的employee对象
//返回一条记录的map;map对象中key就是列名,值就是对应的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);
<!--public Map<String, Object> getEmpByIdReturnMap(Integer id); --> <select id="getEmpByIdReturnMap" resultType="map"> select * from tbl_employee where id=#{id} </select>
@Test public void test04() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //1、获取到的SqlSession不会自动提交数据 SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Map<String, Object> map = mapper.getEmpByIdReturnMap(1); System.out.println("map is:"+map); for(String s:map.keySet()){ System.out.println("key : "+s+" value : "+map.get(s)); } }finally{ openSession.close(); } }
运行打印的结果为
map is:{id=1, email=waawdaw, last_name=sdsfd, gender=1}
key : id value : 1
key : email value : waawdaw
key : last_name value : sdsfd
key : gender value : 1
上面是单条记录的封装,如果是多条记录封装了
/多条记录封装一个map:Map<Integer,Employee>:键是这条记录的主键,值是记录封装后的javaBean //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key @MapKey("lastName") public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);
<!--public Map<Integer, Employee> getEmpByLastNameLikeReturnMap(String lastName); --> <select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where last_name like #{lastName} </select>
resultType指的是集合中的元素,现在我们让map中对应的元素value值是一个employ对象,并且让其key为主键的名字,使用了@MapKey("lastName")告诉mybatis封装map的时候使用lastName作为map的主键
我们来看下代码
@Test public void test04() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //1、获取到的SqlSession不会自动提交数据 SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Map<String, Employee> map = mapper.getEmpByLastNameLikeReturnMap("%r%"); System.out.println(map); for(String s:map.keySet()){ System.out.println("key : "+s+" value : "+map.get(s)); } }finally{ openSession.close(); } }
数据库中的值为
返回是一个map对象,map对象的key为上面使用了@Mapkey指定的值。value为最后一条记录封装的employee对象,我们来看下打印
{jerry4=Employee [id=7, lastName=jerry4, email=null, gender=1]}
key : jerry4 value : Employee [id=7, lastName=jerry4, email=null, gender=1]
28.尚硅谷_MyBatis_映射文件_select_resultMap_自定义结果映射规则.avi
上面中java bean对象的属性名称和表的列名不是一一对应的上面的lastName对应表的last_name上面使用了在sql查询的时候启别名的方式来解决,下面也可以采用resultMap的方式来解决
在说明resultmap之前我们先增加一个部门信息。每个员工对应一个部门。在查出员工的时候对象的将员工的部门信息查询出来,查询部门的时候将对应员工的信息页查询出来
Department
package com.atguigu.mybatis.bean; import java.util.List; public class Department { private Integer id; private String departmentName; private List<Employee> emps; public List<Employee> getEmps() { return emps; } public void setEmps(List<Employee> emps) { this.emps = emps; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDepartmentName() { return departmentName; } public void setDepartmentName(String departmentName) { this.departmentName = departmentName; } @Override public String toString() { return "Department [id=" + id + ", departmentName=" + departmentName + "]"; } }
在数据库中创建tbl_dept表
CREATE TABLE `tbl_dept` ( `id` int(11) NOT NULL AUTO_INCREMENT, `dept_name` varchar(222) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
同时需要修改员工表,让员工表和部门表做管理,给员工表新建一个d_id的字段
CREATE TABLE `tbl_employee` ( `id` int(11) NOT NULL AUTO_INCREMENT, `last_name` varchar(255) DEFAULT NULL, `gender` varchar(1) DEFAULT NULL, `email` varchar(255) DEFAULT NULL, `d_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `ss` (`d_id`), CONSTRAINT `ss` FOREIGN KEY (`d_id`) REFERENCES `tbl_dept` (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
员工类如下
package com.atguigu.mybatis.bean; import org.apache.ibatis.type.Alias; @Alias("emp") public class Employee { private Integer id; private String lastName; private String email; private String gender; private Department dept; public Employee() { super(); } public Employee(Integer id, String lastName, String email, String gender) { super(); this.id = id; this.lastName = lastName; this.email = email; this.gender = gender; } public Department getDept() { return dept; } public void setDept(Department dept) { this.dept = dept; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } @Override public String toString() { return "Employee [id=" + id + ", lastName=" + lastName + ", email=" + email + ", gender=" + gender + ", dept=" + dept + "]"; } }
EmployeeMapperPlus.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.atguigu.mybatis.dao.EmployeeMapperPlus"> <!--自定义某个javaBean的封装规则 type:自定义规则的Java类型 id:唯一id方便引用 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MySimpleEmp"> <!--指定主键列的封装规则 id定义主键会底层有优化; column:指定哪一列 property:指定对应的javaBean属性 --> <id column="id" property="id"/> <!-- 定义普通列封装规则 --> <result column="last_name" property="lastName"/> <!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 --> <result column="email" property="email"/> <result column="gender" property="gender"/> </resultMap> <!-- resultMap:自定义结果集映射规则; --> <!-- public Employee getEmpById(Integer id); --> <select id="getEmpById" resultMap="MySimpleEmp"> select * from tbl_employee where id=#{id} </select> <!-- 场景一: 查询Employee的同时查询员工对应的部门 Employee===Department 一个员工有与之对应的部门信息; id last_name gender d_id did dept_name (private Department dept;) --> <!-- 联合查询:级联属性封装结果集 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap> <!-- 使用association定义关联的单个对象的封装规则; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <!-- association可以指定联合的javaBean对象 property="dept":指定哪个属性是联合的对象 javaType:指定这个属性对象的类型[不能省略] --> <association property="dept" javaType="com.atguigu.mybatis.bean.Department"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> </association> </resultMap> <!-- public Employee getEmpAndDept(Integer id);--> <select id="getEmpAndDept" resultMap="MyDifEmp"> SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=#{id} </select> <!-- 使用association进行分步查询: 1、先按照员工id查询员工信息 2、根据查询员工信息中的d_id值去部门表查出部门信息 3、部门设置到员工中; --> <!-- id last_name email gender d_id --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- association定义关联对象的封装规则 select:表明当前属性是调用select指定的方法查出的结果 column:指定将哪一列的值传给这个方法 流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性 --> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </resultMap> <!-- public Employee getEmpByIdStep(Integer id);--> <select id="getEmpByIdStep" resultMap="MyEmpByStep"> select * from tbl_employee where id=#{id} <if test="_parameter!=null"> and 1=1 </if> </select> <!-- 可以使用延迟加载(懒加载);(按需加载) Employee==>Dept: 我们每次查询Employee对象的时候,都将一起查询出来。 部门信息在我们使用的时候再去查询; 分段查询的基础之上加上两个配置: --> <!-- ==================association============================ --> <!-- 场景二: 查询部门的时候将部门对应的所有员工信息也查询出来:注释在DepartmentMapper.xml中 --> <!-- public List<Employee> getEmpsByDeptId(Integer deptId); --> <select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where d_id=#{deptId} </select> <!-- =======================鉴别器============================ --> <!-- <discriminator javaType=""></discriminator> 鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为 封装Employee: 如果查出的是女生:就把部门信息查询出来,否则不查询; 如果是男生,把last_name这一列的值赋值给email; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- column:指定判定的列名 javaType:列值对应的java类型 --> <discriminator javaType="string" column="gender"> <!--女生 resultType:指定封装的结果类型;不能缺少。/resultMap--> <case value="0" resultType="com.atguigu.mybatis.bean.Employee"> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </case> <!--男生 ;如果是男生,把last_name这一列的值赋值给email; --> <case value="1" resultType="com.atguigu.mybatis.bean.Employee"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="last_name" property="email"/> <result column="gender" property="gender"/> </case> </discriminator> </resultMap> </mapper>
注意:resultType和resultMap只能二选一
<!-- resultMap:自定义结果集映射规则; --> <!-- public Employee getEmpById(Integer id); --> <select id="getEmpById" resultMap="MySimpleEmp"> select * from tbl_employee where id=#{id} </select>
我们在封装下EmployeeMapperPlus.java对象
package com.atguigu.mybatis.dao; import java.util.List; import com.atguigu.mybatis.bean.Employee; public interface EmployeeMapperPlus { public Employee getEmpById(Integer id); public Employee getEmpAndDept(Integer id); public Employee getEmpByIdStep(Integer id); public List<Employee> getEmpsByDeptId(Integer deptId); }
我们来分析下查询员工的时候同时将员工的部门信息查询出来 public Employee getEmpAndDept(Integer id);
在EmployeeMapperPlus.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.atguigu.mybatis.dao.EmployeeMapperPlus"> <!--自定义某个javaBean的封装规则 type:自定义规则的Java类型 id:唯一id方便引用 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MySimpleEmp"> <!--指定主键列的封装规则 id定义主键会底层有优化; column:指定哪一列 property:指定对应的javaBean属性 --> <id column="id" property="id"/> <!-- 定义普通列封装规则 --> <result column="last_name" property="lastName"/> <!-- 其他不指定的列会自动封装:我们只要写resultMap就把全部的映射规则都写上。 --> <result column="email" property="email"/> <result column="gender" property="gender"/> </resultMap> <!-- resultMap:自定义结果集映射规则; --> <!-- public Employee getEmpById(Integer id); --> <select id="getEmpById" resultMap="MySimpleEmp"> select * from tbl_employee where id=#{id} </select> <!-- 场景一: 查询Employee的同时查询员工对应的部门 Employee===Department 一个员工有与之对应的部门信息; id last_name gender d_id did dept_name (private Department dept;) --> <!-- 联合查询:级联属性封装结果集 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap> <!-- 使用association定义关联的单个对象的封装规则; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <!-- association可以指定联合的javaBean对象 property="dept":指定哪个属性是联合的对象 javaType:指定这个属性对象的类型[不能省略] --> <association property="dept" javaType="com.atguigu.mybatis.bean.Department"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> </association> </resultMap> <!-- public Employee getEmpAndDept(Integer id);--> <select id="getEmpAndDept" resultMap="MyDifEmp"> SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=#{id} </select> <!-- 使用association进行分步查询: 1、先按照员工id查询员工信息 2、根据查询员工信息中的d_id值去部门表查出部门信息 3、部门设置到员工中; --> <!-- id last_name email gender d_id --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- association定义关联对象的封装规则 select:表明当前属性是调用select指定的方法查出的结果 column:指定将哪一列的值传给这个方法 流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性 --> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </resultMap> <!-- public Employee getEmpByIdStep(Integer id);--> <select id="getEmpByIdStep" resultMap="MyEmpByStep"> select * from tbl_employee where id=#{id} <if test="_parameter!=null"> and 1=1 </if> </select> <!-- 可以使用延迟加载(懒加载);(按需加载) Employee==>Dept: 我们每次查询Employee对象的时候,都将一起查询出来。 部门信息在我们使用的时候再去查询; 分段查询的基础之上加上两个配置: --> <!-- ==================association============================ --> <!-- 场景二: 查询部门的时候将部门对应的所有员工信息也查询出来:注释在DepartmentMapper.xml中 --> <!-- public List<Employee> getEmpsByDeptId(Integer deptId); --> <select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee"> select * from tbl_employee where d_id=#{deptId} </select> <!-- =======================鉴别器============================ --> <!-- <discriminator javaType=""></discriminator> 鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为 封装Employee: 如果查出的是女生:就把部门信息查询出来,否则不查询; 如果是男生,把last_name这一列的值赋值给email; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- column:指定判定的列名 javaType:列值对应的java类型 --> <discriminator javaType="string" column="gender"> <!--女生 resultType:指定封装的结果类型;不能缺少。/resultMap--> <case value="0" resultType="com.atguigu.mybatis.bean.Employee"> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </case> <!--男生 ;如果是男生,把last_name这一列的值赋值给email; --> <case value="1" resultType="com.atguigu.mybatis.bean.Employee"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="last_name" property="email"/> <result column="gender" property="gender"/> </case> </discriminator> </resultMap> </mapper>
上面中
<!-- 联合查询:级联属性封装结果集 --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap>
必须和
<!-- public Employee getEmpAndDept(Integer id);-->
<select id="getEmpAndDept" resultMap="MyDifEmp">
SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
WHERE e.d_id=d.id AND e.id=#{id}
</select>
<result column="did"中的别名slql语句一一对应
我们来测试下
@Test public void test05() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class); Employee empAndDept = mapper.getEmpAndDept(1); System.out.println(empAndDept); }finally{ openSession.close(); } }
打印输出为
DEBUG 04-24 07:12:34,290 ==> Preparing: SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=? (BaseJdbcLogger.java:145) DEBUG 04-24 07:12:34,349 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:12:34,374 <== Total: 1 (BaseJdbcLogger.java:145) Employee [id=1, lastName=sdsfd, email=null, gender=1, dept=Department [id=2, departmentName=财务部]]
通过级联操作实现了查询员工的将该员工的部门信息查询出来了。
除了级联操作之后,我们来可以使用下面的assocoiate方式在查询员工的时候将该员工的部门信息查询出来
<!-- 使用association定义关联的单个对象的封装规则; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="gender" property="gender"/> <!-- association可以指定联合的javaBean对象 property="dept":指定哪个属性是联合的对象 javaType:指定这个属性对象的类型[不能省略] --> <association property="dept" javaType="com.atguigu.mybatis.bean.Department"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> </association> </resultMap> <!-- public Employee getEmpAndDept(Integer id);--> <select id="getEmpAndDept" resultMap="MyDifEmp2"> SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id, d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d WHERE e.d_id=d.id AND e.id=#{id} </select>
执行查询结果同上面一样
assocoiate方式还可以实现分布查询,在介绍之前先做下面的操作
给部门表建立一个业务接口;类
DepartmentMapper
package com.atguigu.mybatis.dao; import com.atguigu.mybatis.bean.Department; public interface DepartmentMapper { public Department getDeptById(Integer id); public Department getDeptByIdPlus(Integer id); public Department getDeptByIdStep(Integer id); }
然后编写对应的xml文件
DepartmentMapper.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.atguigu.mybatis.dao.DepartmentMapper"> <!--public Department getDeptById(Integer id); --> <select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department"> select id,dept_name departmentName from tbl_dept where id=#{id} </select> <!-- public class Department { private Integer id; private String departmentName; private List<Employee> emps; did dept_name || eid last_name email gender --> <!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 --> <resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> <!-- collection定义关联集合类型的属性的封装规则 ofType:指定集合里面元素的类型 --> <collection property="emps" ofType="com.atguigu.mybatis.bean.Employee"> <!-- 定义这个集合中元素的封装规则 --> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> </collection> </resultMap> <!-- public Department getDeptByIdPlus(Integer id); --> <select id="getDeptByIdPlus" resultMap="MyDept"> SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=#{id} </select> <!-- collection:分段查询 --> <resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep"> <id column="id" property="id"/> <id column="dept_name" property="departmentName"/> <collection property="emps" select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId" column="{deptId=id}" fetchType="lazy"></collection> </resultMap> <!-- public Department getDeptByIdStep(Integer id); --> <select id="getDeptByIdStep" resultMap="MyDeptStep"> select id,dept_name from tbl_dept where id=#{id} </select> <!-- 扩展:多列的值传递过去: 将多列的值封装map传递; column="{key1=column1,key2=column2}" fetchType="lazy":表示使用延迟加载; - lazy:延迟 - eager:立即 --> </mapper>
assocoiate方式还可以实现分布查询,在查询员工的同时查询出对应的部门,如何分布查询出对应的结果了
第一步:查询的员工的时候获得部门的d_id
第二步:使用部门id在部门表中去查询
我们来看下实现public Employee getEmpByIdStep(Integer id);
在EmployeeMapperPlus.xml
<!-- 使用association进行分步查询: 1、先按照员工id查询员工信息 2、根据查询员工信息中的d_id值去部门表查出部门信息 3、部门设置到员工中; --> <!-- id last_name email gender d_id --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- association定义关联对象的封装规则 select:表明当前属性是调用select指定的方法查出的结果 column:指定将哪一列的值传给这个方法 流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性 --> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </resultMap> <!-- public Employee getEmpByIdStep(Integer id);--> <select id="getEmpByIdStep" resultMap="MyEmpByStep"> select * from tbl_employee where id=#{id} <if test="_parameter!=null"> and 1=1 </if> </select>
我来重点分析下
<association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association>
上面中的的dept必须是private Department dept;中的一一对应
select表示我要获得property="dept"指定对象的值通过那个方法来查询获得
com.atguigu.mybatis.dao.DepartmentMapper.getDeptById这个在DepartmentMapper.xml中进行了实现
第三个参数:在执行com.atguigu.mybatis.dao.DepartmentMapper.getDeptById需要传入一个参数,我们在执行 select * from tbl_employee where id=#{id}会得到d_id的值,我们需要将这个d_id的值赋值给com.atguigu.mybatis.dao.DepartmentMapper.getDeptById,我们就使用
column="d_id"来指定,这个d_id是员工表中的列名d_id
我们来测试下
@Test public void test05() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ EmployeeMapperPlus mapper = openSession.getMapper(EmployeeMapperPlus.class); Employee employee = mapper.getEmpByIdStep(3); System.out.println(employee); System.out.println(employee.getDept()); }finally{ openSession.close(); } }
我们来看下打印的结果
DEBUG 04-24 07:38:05,624 ==> Preparing: select * from tbl_employee where id=? and 1=1 (BaseJdbcLogger.java:145) DEBUG 04-24 07:38:05,686 ==> Parameters: 3(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:38:05,756 <== Total: 1 (BaseJdbcLogger.java:145) DEBUG 04-24 07:38:05,757 ==> Preparing: select id,dept_name departmentName from tbl_dept where id=? (BaseJdbcLogger.java:145) DEBUG 04-24 07:38:05,758 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:38:05,761 <== Total: 1 (BaseJdbcLogger.java:145) Employee [id=3, lastName=jerry4, email=null, gender=1, dept=Department [id=1, departmentName=研发部]] Department [id=1, departmentName=研发部]
我们可以看出分布查询上面发出了两条sql查阅语句
场景二:在查询部门的时候将该部门下面的所有员工信息查询出来
DepartmentMapper.java业务接口类
package com.atguigu.mybatis.dao; import com.atguigu.mybatis.bean.Department; public interface DepartmentMapper { public Department getDeptById(Integer id); public Department getDeptByIdPlus(Integer id); public Department getDeptByIdStep(Integer id); }
上面的sql语句要使用左连接。左连接的作用是即使部门下面不存在任何员工也会将该部门的值显示出来,如果去掉left只会查询出存在员工的部门,会存在部门丢失
方式一:
DepartmentMapper.xml
<!--嵌套结果集的方式,使用collection标签定义关联的集合类型的属性封装规则 --> <resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept"> <id column="did" property="id"/> <result column="dept_name" property="departmentName"/> <!-- collection定义关联集合类型的属性的封装规则 ofType:指定集合里面元素的类型 --> <collection property="emps" ofType="com.atguigu.mybatis.bean.Employee"> <!-- 定义这个集合中元素的封装规则 --> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> </collection> </resultMap> <!-- public Department getDeptByIdPlus(Integer id); --> <select id="getDeptByIdPlus" resultMap="MyDept"> SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=#{id} </select>
我们来测试下
@Test public void test06() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class); Department department = mapper.getDeptByIdPlus(1); System.out.println(department); System.out.println(department.getEmps()); }finally{ openSession.close(); } }
运行结果如下
DEBUG 04-24 07:52:12,669 ==> Preparing: SELECT d.id did,d.dept_name dept_name, e.id eid,e.last_name last_name,e.email email,e.gender gender FROM tbl_dept d LEFT JOIN tbl_employee e ON d.id=e.d_id WHERE d.id=? (BaseJdbcLogger.java:145) DEBUG 04-24 07:52:12,734 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:52:12,757 <== Total: 1 (BaseJdbcLogger.java:145) Department [id=1, departmentName=研发部] [Employee [id=3, lastName=jerry4, email=null, gender=1, dept=null]]
实现的第二种方式,使用分段查询public Department getDeptByIdStep(Integer id);
<!-- collection:分段查询 --> <resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep"> <id column="id" property="id"/> <id column="dept_name" property="departmentName"/> <collection property="emps" select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId" column="{deptId=id}" fetchType="lazy"></collection> </resultMap> <!-- public Department getDeptByIdStep(Integer id); --> <select id="getDeptByIdStep" resultMap="MyDeptStep"> select id,dept_name from tbl_dept where id=#{id} </select> <!-- 扩展:多列的值传递过去: 将多列的值封装map传递; column="{key1=column1,key2=column2}" fetchType="lazy":表示使用延迟加载; - lazy:延迟 - eager:立即 -->
我们来测试下
@Test public void test06() throws IOException{ SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); SqlSession openSession = sqlSessionFactory.openSession(); try{ DepartmentMapper mapper = openSession.getMapper(DepartmentMapper.class); Department deptByIdStep = mapper.getDeptByIdStep(1); System.out.println(deptByIdStep.getDepartmentName()); System.out.println(deptByIdStep.getEmps()); }finally{ openSession.close(); } }
DEBUG 04-24 07:59:20,628 ==> Preparing: select id,dept_name from tbl_dept where id=? (BaseJdbcLogger.java:145) DEBUG 04-24 07:59:20,693 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:59:20,765 <== Total: 1 (BaseJdbcLogger.java:145) 研发部 DEBUG 04-24 07:59:20,766 ==> Preparing: select * from tbl_employee where d_id=? (BaseJdbcLogger.java:145) DEBUG 04-24 07:59:20,767 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:145) DEBUG 04-24 07:59:20,770 <== Total: 1 (BaseJdbcLogger.java:145) [Employee [id=3, lastName=jerry4, email=null, gender=1, dept=null]]
运行结果发出了两条sql语句
上面存在一个知识点
<!-- 扩展:多列的值传递过去:
将多列的值封装map传递;
column="{key1=column1,key2=column2}"
fetchType="lazy":表示使用延迟加载;
- lazy:延迟
- eager:立即
-->
column="{deptId=id}" 中deptId对应的是select方法中com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId对的#{deptid}一一对应,value值id对应的就是数据库中部门表中列名id
<!-- public List<Employee> getEmpsByDeptId(Integer deptId); -->
<select id="getEmpsByDeptId" resultType="com.atguigu.mybatis.bean.Employee">
select * from tbl_employee where d_id=#{deptId}
</select>
接下来我们实现下面的规则:如果查询出来的是女生,我们将该员工的部门查询出来,如果是男生,将该员工的信息设置为name的值如何实现了
我们可以使用鉴别器来实现
<!-- =======================鉴别器============================ --> <!-- <discriminator javaType=""></discriminator> 鉴别器:mybatis可以使用discriminator判断某列的值,然后根据某列的值改变封装行为 封装Employee: 如果查出的是女生:就把部门信息查询出来,否则不查询; 如果是男生,把last_name这一列的值赋值给email; --> <resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- column:指定判定的列名 javaType:列值对应的java类型 --> <discriminator javaType="string" column="gender"> <!--女生 resultType:指定封装的结果类型;不能缺少。/resultMap--> <case value="0" resultType="com.atguigu.mybatis.bean.Employee"> <association property="dept" select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById" column="d_id"> </association> </case> <!--男生 ;如果是男生,把last_name这一列的值赋值给email; --> <case value="1" resultType="com.atguigu.mybatis.bean.Employee"> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <result column="last_name" property="email"/> <result column="gender" property="gender"/> </case> </discriminator> </resultMap>
posted on 2018-04-23 21:37 luzhouxiaoshuai 阅读(1589) 评论(1) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!