本文共 20447 字,大约阅读时间需要 68 分钟。
MyBatis是一个半自动化的持久化层框架。
• JDBC – SQL夹在Java代码块里,耦合度高导致硬编码内伤 – 维护不易且实际开发需求中sql是有变化,频繁修改的情况多见 • Hibernate和JPA – 长难复杂SQL,对于Hibernate而言处理也不容易 – 内部自动生产的SQL,不容易做特殊优化。 – 基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难。 导致数据库性能下降。 • 对开发人员而言,核心sql还是需要自己优化 • sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据。package bao;public class User { private String username;private String password;public String getUsername() { return username;}public void setUsername(String username) { this.username = username;}public String getPassword() { return password;}public void setPassword(String password) { this.password = password;}@Overridepublic String toString() { return "User [password=" + password + ", username=" + username + "]";}public User() { super();}}
创建MyBatis全局配置文件mybatis-config.xml
– MyBatis 的全局配置文件包含了影响 MyBatis 行为甚深 的设置(settings)和属性(properties)信息、如数据 库连接池信息等。指导着MyBatis进行工作。我们可以 参照官方文件的配置示例。创建SQL映射文件 EmployeeMapper.xml文件
– 映射文件的作用就相当于是定义Dao接口的实现类如何 工作。这也是我们使用MyBatis时编写的最多的文件。测试类
1、根据全局配置文件,利用SqlSessionFactoryBuilder创建SqlSessionFactory 2、使用SqlSessionFactory获取sqlSession对象。一个SqlSession对象代表和数据库的一次会话package bao;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;public class MyBatisTest { /** * 1、根据xml配置文件(全局配置文件)创建一个SqlSessionFactory对象 有数据源一些运行环境信息 * 2、sql映射文件;配置了每一个sql,以及sql的封装规则等。 * 3、将sql映射文件注册在全局配置文件中 * 4、写代码: * 1)、根据全局配置文件得到SqlSessionFactory; * 2)、使用sqlSession工厂,获取到sqlSession对象使用他来执行增删改查 * 一个sqlSession就是代表和数据库的一次会话,用完关闭 * 3)、使用sql的唯一标志来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。 * * @throws IOException */ // 2、获取sqlSession实例,能直接执行已经映射的sql语句 // sql的唯一标识:statement Unique identifier matching the statement to use. // 执行sql要用的参数:parameter A parameter object to pass to the statement. public static void main(String []args) throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession session = sqlSessionFactory.openSession(); try { System.out.println("segerh"); User blog = session.selectOne("dao.selectUser","df"); System.out.println(blog); } finally { session.close(); } }}
布局
在以上基础上做 先写一个借口
package bao;public interface EmployeeMapper { public User getEmpById(String id);}
映射文件改变如下EmployeeMapper.xml
测试类
package bao;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;/** * 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 static void main(String []args) throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); User employee = mapper.getEmpById("df"); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } public static SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }}
如果属性在不只一个地方进行了配置,那么 MyBatis 将按照下面的顺序来加载:
– 在 properties 元素体内指定的属性首先被读取。 – 然后根据 properties 元素中的 resource 属性读取类路径下属性文件或根 据 url 属性指定的路径读取属性文件,并覆盖已读取的同名属性。 – 最后读取作为方法参数传递的属性,并覆盖已读取的同名属性。 例子: 在同类下建一个.properties文件这是 MyBatis 中极为重要的调整设置,它们会改变MyBatis 的运行时行为。
例如:• 类型别名是为 Java 类型设置一个短的名字,可以方便我们引用某个类。
• 类很多的情况下,可以批量设置别名这个包下的每一个类 创建一个默认的别名,就是简单类名小写。 • 也可以使用@Alias注解为其指定一 例子: 在全局配置文件中 configuration内加入:在User.java进行注解
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。
在这里插入图片描述
插件是MyBatis提供的一个非常强大的机制,我们可以通过插件来修改MyBatis的一些核心行为。插件通过动态代理机制,可以介入四大对象的任何一个方法的执行。
• Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) • ParameterHandler (getParameterObject, setParameters) • ResultSetHandler (handleResultSets, handleOutputParameters) • StatementHandler (prepare, parameterize, batch, update, query)• MyBatis可以配置多种环境,比如开发、测试和生产环境需要有不同的配置。
• 每种环境使用一个environment标签进行配置并指定唯一标识符 • 可以通过environments标签中的default属性指定一个环境的标识符来快速的切换环境在全局配置文件mybatis-config.xml
MyBatis 可以根据不同的数据库厂商执行不同的语句。
• Type: DB_VENDOR – 使用MyBatis提供的VendorDatabaseIdProvider解析数据库厂商标识。也可以实现DatabaseIdProvider接口来自定义。 • Property-name:数据库厂商标识 • Property-value:为标识起一个别名,方便SQL语句使用databaseId属性引用 • DB_VENDOR – 会通过 DatabaseMetaData#getDatabaseProductName() 返回的字符串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不同版本会返回不同的值,所以最好通过设置属性别名来使其变短 • MyBatis匹配规则如下: – 1、如果没有配置databaseIdProvider标签,那么databaseId=null – 2、如果配置了databaseIdProvider标签,使用标签配置的name去匹配数据库信息,匹配上设置databaseId=配置指定的值,否则依旧为null – 3、如果databaseId不为null,他只会找到配置databaseId的sql语句 – 4、MyBatis 会加载不带 databaseId 属性和带有匹配当前数据库databaseId 属性的所有语句。如果同时找到带有 databaseId 和不带databaseId 的相同语句,则后者会被舍弃。 在全局配置文件mybatis-config.xml//////映射文件EmployeeMapper.xml
在前面的基础上
mybatis-config.xml//接口1package bao;import com.atguigu.mybatis.bean.Employee;public interface EmployeeMapper { public Employee getEmpById(Integer id);}////接口2package bao;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);}
• 映射文件指导着MyBatis如何进行数据库增删改查,有着非常重要的意义;
•cache –命名空间的二级缓存配置 •cache-ref – 其他命名空间缓存配置的引用。 •resultMap – 自定义结果集映射 •parameterMap – 已废弃!老式风格的参数映射 •sql –抽取可重用语句块。 •insert – 映射插入语句 •update – 映射更新语句 •delete – 映射删除语句 •select – 映射查询语句package bao;import org.apache.ibatis.annotations.Select;public interface EmployeeMapper { public User getEmpById(String id); public Long addEmp(User employee); public boolean updateEmp(User employee); public void deleteEmpById(String s);}///映射文件/////测试类package bao;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;/** * 测试增删改 * 1、mybatis允许增删改直接定义以下类型返回值 * Integer、Long、Boolean、void * 2、我们需要手动提交数据 * sqlSessionFactory.openSession();===》手动提交 * sqlSessionFactory.openSession(true);===》自动提交 */public class MyBatisTest { public static void main(String []args) throws IOException { // 1、获取sqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); // 2、获取sqlSession对象 SqlSession openSession = sqlSessionFactory.openSession(); try { // 3、获取接口的实现类对象 //会为接口自动的创建一个代理对象,代理对象去执行增删改查方法 EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); User employee = new User("user","woain"); mapper.addEmp(employee); System.out.println(mapper.updateEmp(employee)); mapper.deleteEmpById("user"); openSession.commit(); System.out.println(mapper.getClass()); System.out.println(employee); } finally { openSession.close(); } } public static SqlSessionFactory getSqlSessionFactory() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); return new SqlSessionFactoryBuilder().build(inputStream); }} insert into USER1(USERNAME,PASSWORD) values(#{ username},#{ password}) update USER1 set PASSWORD=#{ password}where USERNAME=#{ username} delete from USER1 where USERNAME=#{ username}
若数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),则可以设置
useGeneratedKeys=”true”,然后再把keyProperty 设置到目标属性上。 将上面映射文件中的添加语句改为/**获取自增主键的值: mysql支持自增主键,自增主键值的获取,mybatis也是利用statement.getGenreatedKeys(); useGeneratedKeys="true";使用自增主键获取主键值策略 keyProperty;指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性*/insert into USER1(PASSWORD) values(#{ password})
上面测试类部分改为(前提在数据库表中username设为自增字段)
User employee = new User(null,"26woain"); mapper.addEmp(employee); System.out.println(employee.getUsername()); //mapper.deleteEmpById("user"); openSession.commit();
而对于不支持自增型主键的数据库(例如Oracle),则可以使用 selectKey 子元素:
selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用 在映射文件中加入select EMPLOYEES_SEQ.nextval from dual insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) values(#{ id},#{ lastName},#{ email })
单个参数:mybatis不会做特殊处理,
#{参数名/任意名}:取出参数值。多个参数:mybatis会做特殊处理。
多个参数会被封装成 一个map, key:param1…paramN,或者参数的索引也可以 value:传入的参数值 #{}就是从map中获取指定的key的值;异常:
org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found. Available parameters are [1, 0, param1, param2] 操作: 方法:public Employee getEmpByIdAndLastName(Integer id,String lastName); 取值:#{id},#{lastName} 例子 全局配置文件EmployeeMapper.xml改善//接口查询多参可看下面
【命名参数】:明确指定封装参数时map的key;@Param(“id”)
多个参数会被封装成 一个map, key:使用@Param注解指定的值 value:参数值 #{指定的key}取出对应的参数值 接口变化如下//bao.EmployeeMapperpublic User getEmpById(@Param("id")String id,@Param("s")String s);//映射文件查询变化select * from USER1 where USERNAME = #{ id} and Password=#{ s}
POJO:
如果多个参数正好是我们业务逻辑的数据模型,我们就可以直接传入pojo; #{属性名}:取出传入的pojo的属性值 Map: 如果多个参数不是业务模型中的数据,没有对应的pojo,不经常使用,为了方便,我们也可以传入map #{key}:取出map中对应的值 例子://EmployeeMapper.java在上面基础上加入public User getmap(Mapmap);////映射文件在上面基础上EmployeeMapper.xml /////测试文件MybatisText.javaMap map = new HashMap (); map.put("id", 1); User employee = mapper.getmap(map); System.out.println(employee);
TO:
如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO(Transfer Object)数据传输对象 Page{ int index; int size; } 拓展: public Employee getEmp(@Param(“id”)Integer id,String lastName); 取值:id==>#{id/param1} lastName==>#{param2}public Employee getEmp(Integer id,@Param(“e”)Employee emp);
取值:id==>#{param1} lastName===>#{param2.lastName/e.lastName}注意:如果是Collection(List、Set)类型或者是数组,也会特殊处理。也是把传入的list或者数组封装在map中。
key:Collection(collection),如果是List还可以使用这个key(list) 数组(array) public Employee getEmpById(List ids); 取值:取出第一个id的值: #{list[0]}#{}:可以获取map中的值或者pojo对象属性的值;
${}:可以获取map中的值或者pojo对象属性的值;select * from tbl_employee where id=${id} and last_name=#{lastName}
Preparing: select * from tbl_employee where id=2 and last_name=? 区别: #{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入 ${}:取出的值直接拼装在sql语句中;会有安全问题; 大多情况下,我们去参数的值都应该去使用#{};原生jdbc不支持占位符的地方我们就可以使用${}进行取值 比如分表、排序。。。;按照年份分表拆分 select * from ${year}_salary where xxx; select * from tbl_employee order by ${f_name} ${order}
例子:
在以前的基础上//测试bao.MyBatisTestEmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class); Mapmap = new HashMap (); map.put("id", 1); map.put("user", "USER1"); User employee = mapper.getmap(map); System.out.println(employee); openSession.commit()/////映射文件/mybaits/src/bao/EmployeeMapper.xml
#{}:更丰富的用法:
规定参数的一些规则: javaType、 jdbcType、 mode(存储过程)、 numericScale、 resultMap、 typeHandler、 jdbcTypeName、 expression(未来准备支持的功能);jdbcType通常需要在某种特定的条件下被设置: 在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错); JdbcType OTHER:无效的类型;因为mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle不能正确处理; 由于全局配置中:jdbcTypeForNull=OTHER;oracle不支持;两种办法 1、#{email,jdbcType=NULL}; 2、jdbcTypeForNull=NULL
• Select元素来定义查询操作。
• Id:唯一标识符。 – 用来引用这条语句,需要和接口的方法名一致 • parameterType:参数类型。 – 可以不传,MyBatis会根据TypeHandler自动推断 • resultType:返回值类型。 – 别名或者全类名,如果返回的是集合,定义集合中元 素的类型。不能和resultMap同时使用//接口bao.EmployeeMapper.javapublic ListgetEmpsByLastNameLike(String lastName);//映射文件/mybaits/wenjian/EmployeeMapper.xml //测试类System.out.println(mapper.getEmpsByLastNameLike("1%"));
以前面的例子为基础
例子://接口bao.EmployeeMapper.java//多条记录封装一个map:Map:键是这条记录的主键,值是记录封装后的javaBean //@MapKey:告诉mybatis封装这个map的时候使用哪个属性作为map的key@MapKey("username") public Map getEmpByLastNameLikeReturnMap(String lastName); //返回一条记录的map;key就是列名,值就是对应的值 public Map getEmpByIdReturnMap(Integer id);/////映射文件/mybaits/wenjian/EmployeeMapper.xml 测试 System.out.println(mapper.getEmpByIdReturnMap(1)); System.out.println(mapper.getEmpByLastNameLikeReturnMap("123"));
– autoMappingBehavior默认是PARTIAL,开启自动映射的功能。唯一的要求是列名和javaBean属性名一致
– 如果autoMappingBehavior设置为null则会取消自动映射 – 数据库字段命名规范,POJO属性符合驼峰命名法,如A_COLUMNaColumn,我们可以开启自动驼峰命名规则映射功能,mapUnderscoreToCamelCase=true。• constructor - 类在实例化时, 用来注入结果到构造方法中
– idArg - ID 参数; 标记结果作为 ID 可以帮助提高整体效能 – arg - 注入到构造方法的一个普通结果 • id – 一个 ID 结果; 标记结果作为 ID 可以帮助提高整体效能 • result – 注入到字段或 JavaBean 属性的普通结果 • association – 一个复杂的类型关联;许多结果将包成这种类型 – 嵌入结果映射 – 结果映射自身的关联,或者参考一个 • collection – 复杂类型的集 – 嵌入结果映射 – 结果映射自身的集,或者参考一个 • discriminator – 使用结果值来决定使用哪个结果映射 – case – 基于某些值的结果映射 • 嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相同的元 素,或者它可以参照一个外部的结果映射。例子(以前面的例子为基础):
//接口bao.EmployeeMapper.javapublic User getEmpById1(Integer id);////映射文件/mybaits/wenjian/EmployeeMapper.xml/////测试类 System.out.println(mapper.getEmpById1(1));
例子(在以前的例子基础上):
//接口bao.EmployeeMapper.javapublic User getEmpAndDept(Integer id);///User.java 改变如下:package bao;import org.apache.ibatis.type.Alias;public class User { private int username;private String password;private Department dpartment;public Department getDpartment() { return dpartment;}public void setDpartment(Department dpartment) { this.dpartment = dpartment;}public String getPassword() { return password;}public void setPassword(String password) { this.password = password;}public int getUsername() { return username;}public void setUsername(int username) { this.username = username;}@Overridepublic String toString() { return "User [dpartment=" + dpartment + ", password=" + password + ", username=" + username + "]";}public User() { super(); // TODO Auto-generated constructor stub}public User(int username, String password, Department dpartment) { super(); this.username = username; this.password = password; this.dpartment = dpartment;}}///mybaits/src/bao/Department.javapackage bao;public class Department { private int id;private String name;public Department() { super(); // TODO Auto-generated constructor stub}public Department(int id, String name) { super(); this.id = id; this.name = name;}@Overridepublic String toString() { return "Department [id=" + id + ", name=" + name + "]";}public int getId() { return id;}public void setId(int id) { this.id = id;}public String getName() { return name;}public void setName(String name) { this.name = name;}}///映射文件/mybaits/wenjian/EmployeeMapper.xml///测试System.out.println(mapper.getEmpAndDept(1));
• id 和 result 映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段。
复杂对象映射
• POJO中的属性可能会是一个对象 • 我们可以使用联合查询,并以级联属性的方式封装对象。映射文件/mybaits/wenjian/EmployeeMapper.xml
例子(以前面的例子为基础):
//1.给Department.java配置相应的接口DepartmentMapper.javapackage bao;public interface DepartmentMapper { public Department getEmpById10(Integer id);}//2..给Department.java配置相应的映射文件DepartmentMapper.xml//3.映射文件DepartmentMapper.xml注册在全局配置文件中 //4.bao.EmployeeMapper.java接口加入public User getEmpByIdStep(Integer id);/////5.映射文件EmployeeMapper.xml加入 //6.测试System.out.println(mapper.getEmpByIdStep(1));
延迟加载
MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询的时候,按照设 置延迟加载规则推迟对关联对象的select检索。延迟加载可以有效的减少数据库 的压力。 注意:MyBatis的延迟加载只是对关联对象的查询有延迟设置,对于主加载对象 都是直接执行查询语句的。 例子(以前面的例子为基础): 在全局配置文件/mybaits/wenjian/mybatis-config.xml加入(properties之后typeAliases之前)例子(以前面的例子为基础):
//bao.Department.java 加入以下属性以及getsetprivate Listlist;//bao.DepartmentMapper.javapublic Department getDeptByIdPlus(Integer id);///wenjian/DepartmentMapper.xml //测试 DepartmentMapper mapper = openSession.getMapper( DepartmentMapper.class); System.out.println(mapper.getDeptByIdPlus(1));
例子(以前面的例子为基础):
//bao.DepartmentMapper.javapublic Department getDeptByIdStep(Integer id);///wenjian/DepartmentMapper.xml///mybaits/src/bao/EmployeeMapper.javapublic List getEmpsByDeptId(Integer id);///mybaits/wenjian/EmployeeMapper.xml //测试System.out.println(mapper.getDeptByIdStep(1));
例子(以前面的例子为基础):
///wenjian/DepartmentMapper.xml
例子(以前面的例子为基础):
///mybaits/wenjian/EmployeeMapper.xml
转载地址:http://tevdz.baihongyu.com/