分类:JavaEE框架技术原创文章作者: 叮当柠柠
什么是MyBatis?
Mybatis使一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。Mybatis免除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。Mybatis可以通过简单的XML或注解来配置和映射原始类型、接口和Java POJO(Plain Old Java Objects,普通老式Java对象)为数据库中的记录。换句话也就说Mybatis是封装JDBC的一种技术,它运用了ORM的设计思想,对象关系映射(Object Relational Mapping,简称ORM)是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。
MyBatis中的主要组成部分
Resources:资源类用于读取配置文件,在JVM加载时,只创建一次。
代码示例:
InputStreamin=Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder:该类运用了建造者模式,提供了一个建造方法用于创建SqlSessionFactory工厂对象,在创建对象时需要配合Resources类获取的输入流对象来使用。这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
代码示例:
SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().builder(in);
3.SqlSessionFactory:该接口运用了工厂模式,提供一个工厂方法用于创建SqlSession对象。它是属于应用级别的,SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
代码示例:
SqlSessionsqlSession=sqlSessionFactory.openSession();
4.SqlSession:会话对象,用于封装JDBC的连接、操作、结果集,它是Mybatis的核心。每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块或用try来关闭。它有两种执行SQL语句的方式。它是属于线程级别的,它的生命周期随SqlSession的存在而存在。//1.根据SqlSession对象的方法//2.根据SQL映射接口,获取Mapper映射器,创建Mapper接口的代理实现类对象
代码示例:
publicProductqueryProductDetailByProductId(intproductId) {
try(SqlSessionsqlSession=MyBatisUtils.openSqlSession()){
//1.根据映射器中的SQL(namespace+id),查找并执行SQL
//Product product=sqlSession.selectOne("com.apesource.dao.mapper.ProductMapper.queryProductById", productId);
//2.根据SQL映射接口,获取Mapper映射器
//创建Mapper接口的代理实现类对象
ProductMapperproductMapper=sqlSession.getMapper(ProductMapper.class);
System.out.println("Mapper接口的代理实现类对象:"+productMapper);
Productproduct=productMapper.queryProductById(productId);
returnproduct;
}catch(Exceptione) {
e.printStackTrace();
returnnull;
}
}
resultMap="productResultMap"> select * from product_info where product_id = #{pid} MyBatis配置 设置(settings) 主要作用:Mybatis框架运行规则配置 设置(settings)代码示例: 类型别名(typeAliases) 主要作用:设置别名 类型别名(typeAliases)代码示例: 环境配置(environments) 主要作用:元素体中包含了事务管理和连接池的配置 环境配置(environments)代码示例: //属性文件 driver_class=com.mysql.cj.jdbc.Driver jdbc_url=jdbc:mysql://47.108.65.254/ApesourceAggregateData? useSSL=false&serverTimezone=UCT db_username=apesource_stu db_password=Apesource=1024 //配置environments 映射器(mappers) 主要作用:映射器是一些绑定映射语句的接口。映射器接口的实例是从 SqlSession 中获得的。虽然从技术层面上来讲,任何映射器实例的最大作用域与请求它们的 SqlSession 相同。但方法作用域才是映射器实例的最合适的作用域。 也就是说,映射器实例应该在调用它们的方法中被获取,使用完毕之后即可丢弃。 映射器实例并不需要被显式地关闭。尽管在整个请求作用域保留映射器实例不会有什么问题,但是你很快会发现,在这个作用域上管理太多像 SqlSession 的资源会让你忙不过来。 因此,最好将映射器放在方法作用域内。就像下面的例子一样: 代码示例: public Product queryProductDetailByProductId(int productId) { try(SqlSession sqlSession=MyBatisUtils.openSqlSession()){ //根据映射器中的SQL(namespace+id),查找并执行SQL //Product product=sqlSession.selectOne("com.apesource.dao.mapper.ProductMapper.queryProductById", productId); //根据SQL映射接口,获取Mapper映射器 //创建Mapper接口的代理实现类对象 ProductMapper productMapper=sqlSession.getMapper(ProductMapper.class); System.out.println("Mapper接口的代理实现类对象:"+productMapper); Product product=productMapper.queryProductById(productId); return product; } catch (Exception e) { e.printStackTrace(); return null; } } MyBatis XML 映射器 1.常用节点作用总结 select :SQL查询语句节点 SELECT COUNT(record_id) as "总数", (SELECT COUNT(record_id) FROM answer_record WHERE right_answer=submit_answer AND respondent=#{respondent}) as "正确数", (SELECT COUNT(record_id) FROM answer_record WHERE right_answer!=submit_answer AND respondent=#{respondent})as "错误数" FROM answer_record WHERE respondent=#{respondent} update:SQL更新语句节点 update answer_record submit_datetime = now() where record_id = #{recordId} delete:SQL删除语句节点 + DELETE FROM answer_record WHERE record_id=#{recordId} parameterType="list"> DELETE FROM answer_record WHERE record_id IN #{rid} insert:SQL插入语句节点 parameterType="AnswerRecord" useGeneratedKeys="true" keyProperty="recordId" > INSERT INTO answer_record(respondent,question,right_answer,submit_answer,submit_datetime) > > VALUES(#{respondent},#{question},#{rightAnswer},#{submitAnswer},now()) > parameterType="list" useGeneratedKeys="true" keyProperty="recordId"> INSERT INTO answer_record(respondent,question,right_answer,submit_answer,submit_datetime) VALUES ( #{record.respondent}, #{record.question}, #{record.rightAnswer}, #{record.submitAnswer}, now() ) 2.常用属性作用总结 + id 属性:SQL语句别名 + resultType 属性:结果集类型 parameterType 属性:传入参数类型 useGeneratedKeys属性:开启主键回填 keyProperty属性:设置主键回填的属性名称 3.常见SQL映射示例 示例1:普通增加 parameterType="Order" useGeneratedKeys="true" keyProperty="orderId"> insert into order_info(order_user,payment_amount,payment_time,payment_method) values(#{orderUser},#{paymentAmount},#{paymentDateTime},#{paymentMethod}) int insertOrder(Order order); 示例2:批量增加 parameterType="list" useGeneratedKeys="true" keyProperty="recordId"> INSERT INTO answer_record(respondent,question,right_answer,submit_answer,submit_datetime) VALUES ( #{record.respondent}, #{record.question}, #{record.rightAnswer}, #{record.submitAnswer}, now() ) int insertAnswerRecordBatch(List 示例3:普通删除 DELETE FROM answer_record WHERE record_id=#{recordId} int deleteAnswerRecord(@Param("id")int recordId); 示例4:批量删除 parameterType="list"> DELETE FROM answer_record WHERE record_id IN #{rid} int insertAnswerRecordBatch(List 示例5:动态修改 update answer_record submit_datetime = now() where record_id = #{recordId} int updateAnswerRecord(AnswerRecord answerRecord); 示例6:动态查询 List 示例7:查询结果封装为Map SELECT COUNT(record_id) as "总数", (SELECT COUNT(record_id) FROM answer_record WHERE right_answer=submit_answer AND respondent=#{respondent}) as "正确数", (SELECT COUNT(record_id) FROM answer_record WHERE right_answer!=submit_answer AND respondent=#{respondent})as "错误数" FROM answer_record WHERE respondent=#{respondent} Map