MyBatis——简介

一、简介
 MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO(Plain Ordinary Java Object,即普通的 Java对象)映射成数据库中的记录。
 简单来说,MyBatis的优点就是将SQL和Java编码分开,功能边界清晰,一个专注业务、一个专注数据。

二、环境搭建
 1、引入MyBatis相关Jar包
 2、创建数据库和数据表:MyBatis不能自动建表,表需手动创建,也可结合JPA,由JPA负责自动建表
 3、创建和表对应的实体类:该类无需任何注解,就是一个纯粹的Java类
 4、创建daos包,并在其下创建XxxMapper接口,并在接口中声明要实现的方法:接口的名字其实是任意的,一般以Mapper作为后缀,该接口无需继承任何其他接口,接口的实现会由MyBatis根据配置来完成

public interface StudentMapper {
    public void add(Student stu);
    public void update(Student stu);
    public void delete(Integer id);
    public Student getById(Integer id);
    public List<Student> getAll();
} 

 5、在XxxMapper接口的同一个包下创建XxxMapper.xml文件:配置内容参照官方文档,该文件的名字是任意的,并非一定要和XxxMapper接口同名,习惯上如此,该配置文件的位置也不强制和接口在同一个包下

<?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指定该映射对应的接口,必须使用全类名,MyBatis会去实现该接口 -->
<mapper namespace="com.bdm.mappers.StudentMapper">
	<!-- id对应接口中声明的方法名,parameterType是方法需要的参数类型(此处使用的全类名,可以在有其他配置的情况下使用简化类名,mybatis支持基本数据类型的简化——有表可查), 
		另外如果方法有返回值的话,还需要配置resultType属性值为返回值类型,中间部分是该方法要执行的sql语句,记住是存粹的sql语句 -->
	<insert id="add" parameterType="com.bdm.entities.Student">
		INSERT INTO students(id,name,age,email)
		VALUES(#{id},#{name},#{age},#{email})
	</insert>
	<update id="update" parameterType="com.bdm.entities.Student">
		UPDATE students 
		SET name=#{name},age=#{age},email=#{email}
		WHERE id=#{id}
	</update>
	<delete id="delete" parameterType="integer">
		DELETE FROM students WHERE id = #{id}
	</delete>
	<select id="getById" parameterType="integer" resultType="com.bdm.entities.Student">
		SELECT * FROM students WHERE id = #{id}
	</select>
	<select id="getAll" resultType="com.bdm.entities.Student">
		SELECT * FROM students
	</select>
</mapper>

 6、配置MyBatis的核心配置文件: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">
			<!-- 事务控制由于尚未引入Spring等,暂且使用基础的JDBC进行事物控制 -->
			<transactionManager type="JDBC" />
			<!-- 配置数据源,也可引用c3p0外部文件 -->
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.cj.jdbc.Driver" />
				<!--若使用高版本的Mysql驱动,则需要配置serverTimezone参数,否则会报时区错误-->
				<property name="url" value="jdbc:mysql:///smve_test?serverTimezone=UTC" />
				<property name="username" value="root" />
				<property name="password" value="123456" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 映射的文件,也可以是类:框架根据此处的配置创建相应的实现类 -->
		<mapper resource="com/bdm/mappers/StudentMapper.xml" />
	</mappers>
</configuration>

 7、添加log4j配置文件:在src根目录下创建log4j.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="log.console" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <!-- 日志的样式 -->
            <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss,SSS} %5p (%C{1}:%M) - %m%n" />
        </layout>
    </appender>
    <logger name="org.apache.ibatis">
        <level value="info" />
        <appender-ref ref="log.console" />
    </logger>
    <!-- 扫描的包名:配置打印哪些包下的日志 -->
    <logger name="com.bdm">
        <level value="debug" />
        <appender-ref ref="log.console" />
    </logger>
</log4j:configuration>  

 8、测试

public class MainTest {

	// mybatis核心配置文件的地址:本例是将其放在了src根目录下
	private static final String SOURCE = "mybatis-config.xml";

	// mybatis中使用sqlSessionFactory获取数据库连接,该对象可以是全局的
	private static SqlSessionFactory sqlSessionFactory = null;
	
	// 相当于数据库连接,该对象必须每个方法一个,不能共用,此处采用切面的方式创建,故将其声明在了外面
	private SqlSession sqlSession = null;

	static {
		InputStream inputStream;
		try {
			// 1、加载配置文件到内存:由此可知该配置文件的名字可以是任意的
			inputStream = Resources.getResourceAsStream(SOURCE);
			// 2、利用该配置文件的配置构建sqlSessionFactory对象
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Before
	public void before() {
		// 3、获取sqlSession对象
		sqlSession = sqlSessionFactory.openSession();
	}

	@Test
	public void test() {
		// 4、调用sqlSession对象的getMapper()方法,获取接口实现类的代理对象,用于调用接口中声明的方法
		StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
		Student stu = new Student();
		stu.setId("1");
		stu.setAge(23);
		stu.setName("tommy");
		stu.setEmail("tommy@qq.com");
		// 5、调用接口中声明的方法
		mapper.add(stu);
	}

	@After
	public void after() {
		try {
			// 6、提交事务,除了查询之外的其他操作都需要提交事务,否则操作不生效,在数据库中看不到效果
			sqlSession.commit();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 7、关闭sessioin
			sqlSession.close();
		}
	}
}

  注意:在实际开发时sqlSession对象不要声明成实例变量,更不要声明成全局变量,而必须是方法内的一个局部变量,因为sqlSession的作用是用来获取数据库连接,类似于Connection,若声明成实例变量或全局变量若其他方法关闭了sqlSession,则再使用时就会报错,即使其他方法不关闭也不好进行事务控制(比如说方法A和方法B使用的是同一个sqlSession,在方法A执行到一半的时候,方法B执行完并调用commit方法提交事务则会将方法A执行到一半的逻辑也提交了,这是错误的)
 流程分析:
  ①sqlSessionFactoryBuilder对象通过build(inputStream)方法读入mybatis-config.xml配置文件,为该文件中配置的mappers接口创建实现类,实现类中会实现哪些方法以及方法怎么实现则由XxxMapper.xml中配置的方法名和功能决定,这也是为什么XxxMapper.xml中的id要和接口的方法名保持一致的原因,否则就无法通过代理类调用方法的实现了(比如接口中声明的方法名为a,XxxMapper.xml中的id为b,则MyBatis为我们创建的实现的对应方法名也会为b而不是a,这样我们在调用我们定义的接口的a方法的时候由于没有对应的实现就不起作用而报错,这一点和SpringData类似)
  ②在使用的时候,通过SqlSession的getMapper(XxxMapper.class)方法获取到接口实现类的代理对象,通过代理对象即可调用接口中声明了的方法,如①中所述这些方法是由MyBatis框架提供的实现

三、注解版MyBatis
 注解版的MyBatis在接口定义的时候有些区别,将方法要执行的SQL在方法声明的时候就指定,这样就摆脱了XxxMapper.xml这个配置文件。但是这样并不好,因为开发中很可能会有一些复杂的SQL,如果写在接口中会很麻烦,而且这也背离了SQL和Java代码分离的初衷,因此最好还是采用XxxMapper.xml配置的方式。如果使用注解版的话,在核心控制文件中的接口就不再是注册XxxMapper.xml文件了,而是注解接口的全类名。
 1、接口:接口中的方法在声明时指定执行的SQL

public interface StudentMapper {

	@Insert("INSERT INTO students(id,name,age,email) VALUES(#{id},#{name},#{age},#{email})")
	public void add(Student stu);

	@Update("UPDATE students SET name = #{name},age = #{age},email = #{email} WHERE id = #{id}")
	public void update(Student stu);

	@Delete("DELETE FROM students WHERE id = #{id}")
	public void delete(Integer id);

	@Select("SELECT * FROM students WHERE id = #{id}")
	public Student getById(Integer id);

	@Select("SELECT * FROM students")
	public List<Student> getAll();
}

 2、核心配置文件:映射的不再是XxxMapper.xml,而是接口的全类名

<mappers>
	<!-- 映射的文件,也可以是类:框架根据此处的配置创建相应的实现类 -->
	<!-- <mapper resource="com/bdm/mappers/StudentMapper.xml" /> -->
	<mapper class="com.bdm.mappers.StudentMapper" />
</mappers>

注意需要特别注意的是,在核心配置文件mybatis-config.xml的\<mappers>节点中无论是采用注册接口全类名的方式还是采用注册XxxMapper.xml文件的方式MyBatis在实现接口的时候都会同时实现这两个地方定义的接口方法,举例来说:假如我在\<mappers>中只注册了<mapper class="com.bdm.mappers.StudentMapper" />,这意味着我想使用注解版的MyBatis,那我必然会在声明方法的时候给方法加上相应的@Insert等注解和SQL,你可能会觉得此时StudentMapper.xml配置文件就不会起作用了,因为mybatis-config.xml中并没有注册StudentMapper.xml,因此StudentMapper.xml是不会被加载的。其实不然,MyBatis会同时扫描同名包下有无和StudentMapper.java接口同名的StudentMapper.xml(不同名则不会加载,更不会实现)文件,如果扫描到了,则在实现方法的时候会同时将StudentMapper.xml中定义的方法也进行实现,那么如果StudentMapper.xml文件中有id和接口方法名同名且入参也和方法名一样的配置时,则会报错!原因很简单,一个类中不能有两个同名且入参也相同的方法。反过来如果你在\<mappers>中只注册<mapper resource="com/bdm/mappers/StudentMapper.xml" />,则MyBatis在实现的时候会扫描同名包下是否有StudentMapper.java接口,然后会去实现StudentMapper.java中标注了@Insert等注解的方法。当然如果接口中声明的方法既没有加注解也没有在XxxMapper.xml中配置,则MyBatis框架不会为我们实现该方法。说了这么多,结论是接口中声明的方法要么只在接口中使用注解,要么只在对应的mapper.xml文件中指明实现方式,这两种方式不能同时存在。但这并不意味着注解版和配置版不能同时存在,我们可以在注解版中实现其中的一部分,另外一部分放在配置中也是可以的。但只能在<mappers>中注册一个,其实注册一个就相当于两种方式都注册了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值