mybatis学习进阶
Posted fzywhy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis学习进阶相关的知识,希望对你有一定的参考价值。
11、mybatis和hibernate本质区别和应用场景
1、hibernate:是一个标准的ORM(对象关系映射),不需要程序员写sql,sql语句自动生成
:对sql语句进行优化,修改困难
适应于需求变化不多的中小型项目,egg:后台管理系统,ERP(enterprise resource planning)ORM(object,relational,Mapping),OA(office automation )system办公自动化,无纸化办公模式。
2、mybatis:专注的是sql,需要程序员编写sql语句,sql优化修改,优化方便
(不完全的ORM框架,可以实现映射(输入映射、输出映射))
适用于需求变化比较多的项目,敏捷式开发(egg:互联网项目)
3、企业技术选型:低成本,高回报作为技术选型的原则,根据项目组的技术力量进行选择。
12、mybatis开发dao的方法
1、SqlSession的使用范围:
SqlSessionFactoryBuilder:将其当成一个工具类使用即可,在需要创建SqlSessionFactory时,只需要new一次SqlSessionFactoryBuilder即可
SqlSessionFactory:使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)
SqlSession:是一个面向用户(程序员)的接口,提供了很多操作数据库的方法
selectOne:
selectList:(返回单个或多个对象)
SqlSession是线程不安全的,在SqlSession实现类中除了有接口中的方法(操作数据库的方法),还有数据域属性,
SqlSession最佳适用场合在方法体内,定义成局部变量使用。
2、原始dao开发方法(程序员写dao接口和dao实现类)
手写dao接口和dao实现类
需要向dao实现类中注入SqlSessionFactory,在方法体通过SqlSessionFactory创建SqlSession
dao接口:
public interface UserDao {
//根据userId查询用户信息
public User findUserById(int userId) throws Exception;
//添加用户信息
public void insertUser(User user) throws Exception;
//删除用户信息
public void deleteUser(int userId) throws Exception;
}
dao:
public class UserDaoImpl implements UserDao {
//需要向dao实现类中注入SqlSessionFactory
//这里通过构造方法注入
private SqlSessionFactory sqlSessionFactory;
public UserDaoImpl(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
}
@Override
public User findUserById(int userId) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("test.findUserById", userId);
sqlSession.close();
return user;
}
@Override
public void insertUser(User user) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.insert("test.insertUser", user);
sqlSession.commit();
sqlSession.close();
}
@Override
public void deleteUser(int userId) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
sqlSession.delete("test.deleteUser", userId);
sqlSession.commit();
sqlSession.close();
}
}
单元测试:
public class UserDaoImplTest {
private SqlSessionFactory sqlSessionFactory;
//此方法是在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
//创建sqlSessionFactory
String resource = "SqlMapConfig.xml";
InputStream config = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(config);
}
@Test
public void testFindUserById() throws Exception {
//创建UserDao的对象
System.out.println("ddddd:"+sqlSessionFactory);
UserDao userDao = new UserDaoImpl(sqlSessionFactory);
//调用UserDao的方法
User user = userDao.findUserById(4);
System.out.println(user);
}
}
原始dao的开发问题:
1、dao接口实现类方法中存在大量模板方法,(提取公共代码)
2、调用sqlSession方法时将statement的userId硬编码了
3、调用sqlSession方法时传入的变量,由于sqlSession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于开发。
3、mapper代理方法(程序员只需要写mapper接口)相当于dao接口
思路: (mapper代理开发规范)
1、编写mapper.xml映射文件
2、编写mapper接口(相当于dao接口),需要遵循一些开发规范,mybatis可以自动生成mapper接口实现类代理对象。
开发规范:
*在mapper.xml中,namespace等于mapper接口地址
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离
注意:使用mapper代理方法开发,namespace有特殊重要的作用
-->
<mapper namespace="com.fzy.mybatis.mapper.UserMapper">
*mapper.java接口中的方法名和mapper.xml中statement的id一致
*mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致
*mapper.java接口中的方法返回值类型和mappe.xml中的resultType指定的类型一致。
public User findUserById(int id) throws Exception;
开发规范主要时对相似代码进行统一生成
测试 :
mapper.java
public interface UserMapper {
public User findUserById(int userId) throws Exception;
mapper.xml
<select id="findUserById" parameterType="int" resultType="com.fzy.mybatis.po.User">
select * from users where userId = #{userId}
</select>
在SqlMapConfig.xml中配置加载mapper.xml
<mapper resource="mapper/UserMapper.xml"/>
测试代码:
public class UserMapperTest {
private SqlSessionFactory sqlSessionFactory;
//此方法时在执行testFindUserById之前执行
@Before
public void setUp() throws Exception {
//创建sqlSessionFactory
String resource = "SqlMapConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindUserById() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
System.out.println("sqlSession:"+sqlSession);
//创建UserMapper的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
System.out.println("userMapper:"+userMapper);
//调用UserMapper的方法
User user = userMapper.findUserById(4);
System.out.println(user);
}
}
问题总结:
1、代理对象内部调用selectOne和selectList
如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库
若mapper方法返回集合对象,代理对象内部通过selectList查询数据库
2、mapper接口方法参数只能有一个是否影响系统开发
系统框架中,dao层的代码时被业务层公用的
即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。
注意:持久层方法的参数可以用包装类型,map,,,service方法中建议不要使用包装类型(不利于业务层的可扩展性)。
13、mybatis的全局配置文件
配置内容:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
enviroument(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
1、properties
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xm中加载db.properties的属性值(解决数据库连接参数硬编码)
将数据库连接参数只配置在db.properties中
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/travel?characterEncoding=utf-8
jdbc.username = root
jdbc.password = 123456
原因:方便对参数进行统一管理,其他的xml文件可以引用该db.properties
<!-- 加载属性文件 -->
<properties resource="db.properties">
<!-- properties中还可以配置一些属性名和属性值 -->
<!-- <property name="" value=""/> -->
</properties>
<!-- 和spring整合后environments配置將移除 -->
<environments default="development">
<environment id="development">
<!-- 使用jdbc事物管理,事物控制由mybatis進行 -->
<transactionManager type="JDBC" />
<!-- 数据库连接池,由mybatis管理 -->
<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>
</environments>
<!-- 加载映射文件 -->
<mappers>
<mapper resource="sqlmap/User.xml"/>
<!-- <mapper class="com.fzy.mybatis.mapper.UserMapper"/> -->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
注:mybatis加载属性的顺序
1、在properties元素体内定义的属性首先被读取
2、其后会读取properties元素中resource或url加载的属性,它会覆盖已读取的同名属性
3、最后读取parameterType传递的属性,它会覆盖已读取的同名属性
so:parameterType传递的属性具有最高优先级,其次是properties中的resource或url,之后是properties元素体内定义的属性。
不要在propeties元素体内添加任何属性值,只将属性值定义在properties文件中,在properties文件中定义属性名要有一定的特殊性,egg:xxx.xxx.xxx
2、settings全局参数配置(需要时再设置)
mybatis框架在运行时可以调整一些运行参数:egg:开启二级缓存,开启延迟加载…
全局参数会影响mybatis的运行行为
3、typeAliases(别名)常用
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型,需要resultType指定输出结果的映射类型
可以针对parameterType和resultType指定的类型定义一些别名,方便开发。
默认别名:
自定义别名:
<!-- 别名定义 -->
<typeAliases>
<!-- 针对单个别名的定义
type:类型的路径
alias:别名 -->
<typeAlias type="com.fzy.mybatis.po.User" alias="user"/>
</typeAliases>
<!-- 批量别名定义
指定包名,mybatis自动扫描包中的po类,自动定义别名,别名就是类名(首字母大小写均可)
-->
<package name="com.fzy.mybatis.po"/>
4、typeHandlers类型处理器
mybatis中通过typeHandlers完成jdbc类型和Java类型的转换
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义
5、mappers(映射配置)
加载单个映射文件(通过resource或url)
<!-- 加载映射文件 -->
<mappers>
<!-- 通过resource方法一次加载一个映射文件 -->
<mapper resource="sqlmap/User.xml"/>
<!-- <mapper class="com.fzy.mybatis.mapper.UserMapper"/> -->
<mapper resource="mapper/UserMapper.xml"/>
</mappers>
通过mapper接口加载单个mapper
<!-- 通过mapper接口加载映射文件
规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中。
前提:使用的是mapper代理方法
-->
<mapper class="com.fzy.mybatis.mapper.UserMapper"/>
根据规范:将mapper.java和mapper.xml放在一个目录中,且同名
批量加载mapper(推荐使用)
<!-- 批量加载mapper
指定mapper接口的包名,mybatis自动扫描包下边所有的mapper接口进行加载
规范:需要将mapper接口类名和mapper.xml映射文件名称保持一致,且在一个目录中。
前提:使用的是mapper代理方法
-->
<package name="com.fzy.mybatis.mapper"/>
以上是关于mybatis学习进阶的主要内容,如果未能解决你的问题,请参考以下文章
Java进阶 - MyBatis查询数据库 && Spring Boot 单元测试 - 细节狂魔
MyBatis案例 | 使用映射配置文件实现CRUD操作——动态SQL优化条件查询