MyBatis是一个半自动化的持久化层框架。
JDBC
SQL夹在Java代码块里,耦合度高导致硬编码内伤
维护不易且实际开发需求中sql是有变化,频繁修改的情况多见Hibernate和JPA
长难复杂SQL,对于Hibernate而言处理也不容易
内部自动生产的SQL,不容易做特殊优化
基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难,导致数据库性能下降对开发人员而言,核心sql还是需要自己优化
sql和java编码分开,功能边界清晰,一个专注业务、一个专注数据
<!-- sql demo-->
CREATE TABLE `employee` (
`id` varchar(50) NOT NULL default '',
`name` varchar(50) default NULL,
`gender` char(1) default NULL,
`address` varchar(100) default NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `employee` VALUES ('1', '张全蛋', '1', '暴走大事件');
INSERT INTO `employee` VALUES ('2', '王尼玛', '1', '暴走大事件');
INSERT INTO `employee` VALUES ('3', '李小华', '0', '富士康');
INSERT INTO `employee` VALUES ('4', '赵铁柱', '1', '富士康');
INSERT INTO `employee` VALUES ('5', '风清扬', '1', '华山');
INSERT INTO `employee` VALUES ('6', '周杰伦', '1', '台北');
INSERT INTO `employee` VALUES ('7', '卡死了', '1', '我说的');
使用步骤:
- 导入jar包
2)添加mybatis全局配置文件,log4j日志文件,数据源信息文件
3)创建实例类(POJO,domain,javaBean,entity),实体类的映射文件(sql映射文件)
4)将映射文件注册到mybatis全局配置文件中
5)编写SQL,根据全局配置文件拿到SqlSessionFactory,通过SqlSessionFactory拿到SqlSession对象,调用封装好的方法进行CRUD,关闭会话。
package com.igeek.pojo;
public class Employee {
private String id ;
private String name;
private char gender;
private String address;
}
<mapper namespace="hello">
<select id="selOne" resultType="com.igeek.pojo.Employee">
select * from employee where id=#{id}
select>
mapper>
try {
//根据全局配置文件。利用SqlSessionFactoryBuilder创建数据库会话工厂对象。
Reader reader = Resources.getResourceAsReader("resource.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//通过会话工厂获取SqlSession对象,一个SqlSession对象代表和数据库的一次会话
SqlSession session = sqlSessionFactory.openSession();
//推荐使用namespace+id,防止多个配置文件中的id重复。
Employee emp = session.selectOne("hello.selOne", "1");
System.out.println(emp);
//每次使用完需要关闭sqlsession对象。(必须)
session.close();
//注意:SqlSession跟connection一样都不是线程安全的,因此不能被共享。不推荐写成成员变量。每次使用重新获取。
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
##4.mybatis三种开发模式
1.请看上面HelloWorld的demo
(存在问题,每次都要指定查询那个命名空间下的那个标签的sql,类型是object类型)
2.使用接口+配置文件
(接口与配置文件动态绑定。mybatis会为接口自动创建代理对象)
(注意:1.需要将namespace中的值,写成接口的全路径 2.接口方法名称跟标签id一致)
(使用接口式优点,有明确的返回值,更严格的类型检查。将规范与实现分离,可以使用不同的持久层技术,方便开发扩展以及维护。)
3.使用接口+注解
SqlSession可以直接调用方法的id进行数据库操作,但是我们一般还是推荐使用SqlSession获取到Dao接口的代理类,执行代理对象的方法,可以更安全的进行类型检查操作。。。 推荐使用第二种开发模式!!!!!
//第二种方式的demo...
@Test
public void test2(){
SqlSession session = getSqlSession();
EmployeeDao employeeDao = session.getMapper(EmployeeDao.class);
System.out.println(employeeDao.getClass());
Employee employee = employeeDao.selOne(2);
System.out.println(employee);
}
//封装一个获取sqlsession对象的方法。
public SqlSession getSqlSession(){
Reader reader=null;
try {
reader = Resources.getResourceAsReader("resource.xml");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//通过会话工厂获取SqlSession对象,一个SqlSession对象代表和数据库的一次会话
SqlSession session = sqlSessionFactory.openSession();
return session;
}
##5.全局配属属性内容
settings
typeAliases
typeHandlers
typeHandlers JDK1.8 日期类 JSR310规范,时间类型处理器。
plugins
环境中的自定义数据源,默认使用mybatis提供的数据源
数据库厂商支持(全局文件中配置完,在映射文件中配置当前SQL在那个数据库环境下执行.)
mapper注册一个SQL映射
<insert id="insertEmp" parameterType="com.igeek.pojo.Employee">
insert into employee values(#{id},#{name},#{gender},#{address})
insert>
<update id="updateEmp">
update employee set name = #{name},gender = #{gender},address=#{address}
where id = #{id}
update>
<delete id="deleteEmp">
delete from employee where id = #{id}
delete>
@Test
public void test2(){
SqlSession session = getSqlSession();
EmployeeDao employeeDao = session.getMapper(EmployeeDao.class);
Employee employee = new Employee();
employee.setId("7");
employeeDao.deleteEmp(employee);
//注意,拿到的sqlSession对象需要手动的提交,接口中的返回值类型可以是void,int long boolean
//可以设置自动提交工厂对象.openSession(true);
session.commit();
session.close();
}
1.当传递的参数只有一个的时候,mybatis不会做特殊处理。
2.当传递多个参数的时候,mybatis会封装一个Map,当前map的key 默认是param1...paramN,取的时候使用key拿到value,也可以通过索引。可以在接口方法中使用@Param注解来直接封装map的key...如果多个参数的话推荐传入POJO,通过#{属性名}来取出。也可以直接在接口声明位置传入一个map集合。如果经常使用可以创建一个TO对象,封装数据信息。(transfer object)
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<Integer> ids);
取值:取出第一个id的值: #{list[0]}
#{}:是以预编译的形式,将参数设置到sql语句中;PreparedStatement;防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,我们去参数的值都应该去使用#{};
sql语句中不支持占位符 ( ? ) 的地方需要使用${}取值 比如orderby 排序。
方法的返回值类型为List嵌套实体类,select标签中resultType指定集合中对象的类型即可。