Mybatis
一、简介
- MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
二、下载
目前mybatis已经放在github上面,点击进入下载
下载压缩包后解压
- mybatis-3.5.6.jar就是所需要的jar,lib下还有其他辅助的jar包
- pdf 文件是帮助文档
三、Hello Mybatis
1.配置环境
- 首先在idea中创建maven项目
在pom中添加如下数据
<dependencies> <!--Mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.6</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>compile</scope> </dependency> </dependencies>
在src/main/resources目录下创建mybatis-config.xml,右键项目选择--》 open Module Sitting
- 点击Resources,然后选择项目中的resources,然后点击OK即可
2.添加配置文件
上述操作中在resources中创建了mybatis-config.xml,根据 pdf 说明,在文件中这样写
<?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"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
修改文件中的连接和地址等
<?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"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/diary?serverTimezone=Asia/Shanghai"/> <property name="username" value="root"/> <property name="password" value=""/> </dataSource> </environment> </environments> <mappers> <mapper resource="DiaryMapper.xml"/> </mappers> </configuration>
注意:
正常写法应是:jdbc:mysql://localhost:3306/diary
但是在不加后面的东西,在运行时会报以下错误:Cause: java.sql.SQLException: The server time zone value
主要是没有设置时区
3.创建测试类
- 在src下创建测试类 mybatis.java
根据 pdf 帮助文档,首先需要根据配置文件 获取 SqlSessionFactory
String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
获取到sqlSessionFactory后即可通过selectOne方法获取一对象
Diary diary = sqlSessionFactory.selectOne("DiaryMapper.selectDiary", 1);
selectOne 有两个参数,第一个是配置文件映射的sql语句,第二个是要传递的参数
@Test public void test() throws IOException { SqlSession session = getSqlSessionFactory().openSession(); try { Diary diary = session.selectOne( "DiaryMapper.selectDiary", 1); System.out.println(diary); }finally { session.close(); } }
在resource下创建sql映射文件 ---》DiaryMapper.xml
<?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"> <mapper namespace="DiaryMapper"> <select id="selectDiary" resultType="Diary"> select * from diaries where id = #{id} </select> </mapper>
在 mybatis-config.xml 中修改最下面的 mappers 映射的文件目录
<mappers> <mapper resource="DiaryMapper.xml"/> </mappers>
四、接口式编程
- 相比上一个方法有很多优点,高解耦,类型检查 ...
创建一个接口来替换代码中的一长串
public interface DiaryMapper { public Diary getDiaryById(Integer id); }
- 将 DiaryMapper.xml中的 namespace 指定为接口的全类名 :
- 将 xml 中的 select id 修改为方法名:
创建测试方法
@Test public void test01() throws IOException { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); //获取 SqlSessionFactory 对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); //获取 Sqlsession 对象 SqlSession session = sqlSessionFactory.openSession(); try { //获取接口实现类对象 //会为接口创建一个代理对象,由代理代理对象执行增删改查 DiaryMapper diaryMapper = session.getMapper(DiaryMapper.class); //调用接口的方法 Diary diary = diaryMapper.getDiaryById(4); System.out.println(diary); } finally { session.close(); } }
五、详解全局配置文件
1.properties
mybatis 可以使用properties标签来引入外部的properties配置文件,其中有两个属性
- resource:引入类路径下的资源
- url:引入网络路径或磁盘路径
在resource下创建 dbconfig.properties文件,将原来 mybatis.xml中的数据源信息提取出来
jdbc.diver=com.mysql.cj.jdbc.Driver #如果使用的是mysql8.0以上要加入时区:serverTimezone=Asia/Shanghai jdbc.url=jdbc:mysql://localhost:3306/diary?serverTimezone=Asia/Shanghai jdbc.username=root jdbc.password=
修改 mybatis.xml中的值,例如:${jdbc.diver}
<properties resource="dbconfig.properties"></properties> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.diver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments>
2.settings
settings包含很多重要的设置项setting:用来设置每一个设置项
name:设置项名
value:设置项取值<settings> <setting name="" value=""/> </settings>
mapUnderscoreTocameLCaseEnables:是否开启自动驼峰命名规则( camel case )映射,即从经典数据库列名A_COLUMN到经典Java属性名aColumn 的类似映射,默认状态是 false;例如 数据库中lastname字段与实体类中的lastName无法匹配即可开启此设置
<settings> <setting name="mapUnderscoreTocameLCaseEnables" value="true"/> </settings>
3.typeAliases(别名处理器)
可以将Java全类名起一个简短的别名
<!--对一个类起别名--> <typeAliases> <!--默认不写alias,别名就是类名小写:diary--> <typeAlias type="club.gaoxu.bean.Diary" alias="新的别名"/> </typeAliases>
<!--对一个包下所有类起别名--> <typeAliases> <!--默认不写alias,别名就是类名小写:diary--> <package type="club.gaoxu.bean"/> </typeAliases>
### 4.plugins ### 5.environments
可以配置多种环境
<environments default="development"> <environment id="test"> <transactionManager type=""></transactionManager> <dataSource type=""></dataSource> </environment> <environment id="development"> <transactionManager type=""></transactionManager> <dataSource type=""></dataSource> </environment> </environments>
transactionManager事务管理器,type是事务管理器的类型,有以下两种
- JDBC
- MANAGED:使用JAVA EE来进行事务控制
- 还可以自定义事务管理器
dataSource 数据源,type有三种
- UNPOOLED:不用连接池
- POOLED:使用连接池
- JNDI:使用 JNDI技术
- 还可以进行自定义数据源,实现DatasourceFactory接口
default指定某种环境。达到快速切换
6.databaseIdProvider
- 多数据库厂商发送sql
- 在配置文件中,写入databaseIdProvider标签,使用property 标签给数据库起别名 Mysql----》mysql,Oracle----》oracle
在sql语句的映射文件的标签下,有dataSourceId属性,填写对应Id即可实现不同厂商数据库的使用
7.mappers
- 将sql映射注册到全局配置中
- mapper标签就是来注册sql标签
- mapper的属性 resource:引用类路径下的sql配置文件,url属性引用网络路径或磁盘路径下的sql配置文件
mapper下的class属性:引用(注册)接口
- 有sql映射文件,映射文件名必须和接口同名,并且放在接口同一目录下
- 没有sql映射文件,所有sql都是利用注解方式
import club.gaoxu.bean.Diary; import org.apache.ibatis.annotations.Select; public interface DiaryMapper { @Select("select * from diaries where id = #{id}") public Diary getDiaryById(Integer id);
- 推荐,在比较重要的,复杂的Dao接口写映射文件,在不重要,简单的Dao接口使用注解快速开发
六、详解SQL映射文件
1.增删改查
首先在DiaryMapper接口中定义相应的增删改查方法
import club.gaoxu.bean.Diary; import org.apache.ibatis.annotations.Select; public interface DiaryMapper { public Diary getDiaryById(Integer id); public void addDiary(Diary diary); public void updataDiary(Diary diary); public void deleteDiaryById(Integer id); }
然后在sql映射文件中使用对应标签创建sql语句,id就是接口的方法名
<?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"> <mapper namespace="DiaryMapper"> <select id="getDiaryById" resultType="diary"> select * from diaries where id = #{id} </select> <!--public void addDiary(Diary diary);--> <insert id="addDiary" parameterType="diary"> insert into diaries(id,title,context,time) values(#{id},#{title},#{context},#{time}) </insert> <!--public void updataDiary(Diary diary);--> <update id="updataDiary"> update diaries set title=#{title},context=#{context},time=#{time} where id=#{id} </update> <!-- public Diary deleteDiaryById(Integer id);--> <delete id="deleteDiaryById"> delete from diaries where id=#{id} </delete> </mapper>
最后在测试类中进行调用
/** * 测试增删改查 * @throws IOException */ @Test public void test02() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //使用不带参数的openSession,不会自动提交数据,也就是需要执行方法后写上commie方法 SqlSession sqlSession = sqlSessionFactory.openSession(); try{ Diary diary = new Diary(); diary.setId(25); diary.setTitle("mybatis测试增删改"); diary.setContext("不知道能不能两次就成功呢"); diary.setTime(new Timestamp(System.currentTimeMillis())); DiaryMapper diaryMapper = sqlSession.getMapper(DiaryMapper.class); diaryMapper.updataDiary(diary); //diaryMapper.deleteDiaryById(24); //diaryMapper.addDiary(diary); //手动提交 sqlSession.commit(); }finally { sqlSession.close(); } }
可以设置方法的返回值类型为:Integer,Long,Boolean
mybatis框架会根据sql的执行情况自动返回对应类型的结果
2.insert获取自增主键的id
- 在实际场景中,往往主键的id是自动生成的,而我们插入后怎么获取相应的id呢
- 原生的JDBC是根据mysql支持的自增主键,statemnet.getGenreatedKeys()
mybaits也是根据上面的方法进行返回,可以在insert的标签内使用 useGenreatedKeys,将这个属性的值设置成true,使用自增主键获取主键值策略,然后再次在insert标签内使用 KeyProperty 指定对应主键属性
<insert id="addDiary" parameterType="diary" useGeneratedKeys="true" keyProperty="id"> insert into diaries(id,title,context,time) values(#{id},#{title},#{context},#{time}) </insert>
在没有设置主键的情况下可以获取生成的id
@Test public void test02() throws IOException { SqlSessionFactory sqlSessionFactory = getSqlSessionFactory(); //使用不带参数的openSession,不会自动提交数据,也就是需要执行方法后写上commie方法 SqlSession sqlSession = sqlSessionFactory.openSession(); try{ Diary diary = new Diary(); diary.setTitle("mybatis测试增删改"); diary.setContext("不知道能不能两次就成功呢"); diary.setTime(new Timestamp(System.currentTimeMillis())); DiaryMapper diaryMapper = sqlSession.getMapper(DiaryMapper.class); diaryMapper.addDiary(diary); System.out.println(diary.getId()); //手动提交 sqlSession.commit(); }finally { sqlSession.close(); } }
3.参数处理,单个、多个参数,命名参数
- 单个参数:#{参数名},就可以取出参数,单个参数mybatis不会过多处理,{ }里面参数名写什么都可以
多个参数:会做特殊处理,多个参数会被封装成一个map,#{}就是从map中取值,
key:param1.... paramN,或者参数的索引 value:传入的参数
- 异常:BindingException
- Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]
- 操作:方法:public Dairy getDiaryById(Integer id,String title)取值:#{id} ,#{title}
注意:多参数 取值:#{id} ,#{title}是错误的,会报以上错误,需要写成 #{param1} ,#{param2},param1,param2并不是其他变量的意思,就这么写
<select id="getDiaryById" resultType="diary">
select * from diaries where id = #{param1} and title = #{param2}
</select>
但是非常不方便,我们可以在接口传递参数的时候进行设置
public Diary getDiaryById(@Param("id") Integer id, @Param("title") String title);
当然,很多时候多参数符合对象的规则,我们直接传递对象即可,传递对象可以直接 #{id} ,#{title} 取值
如果不是对应的对象模型,我们还可以传入map
{key},就是取出map中 的值
传递多参数包含对象
public Diary getDiaryById(Integer id, Diary diary);
取值时:id ---》#{param1},title ---》 #{param2.title}
public Diary getDiaryById(Integer id,@Param("d") Diary diary);
那么取值时可以使用:title ---》 #{d.title}
特别注意,如果是Collection(list,set)类型或数组进行特殊处理,也是封装在map中:<key,collection>,如果是List还可以使用这个key(list),数组(array)
public Diary getDairyById(List<Integer> ids);
引用时:
<select id="getDiaryById" resultType="diary"> select * from diaries where id = #{list[0]} </select>
4.$与#取值的区别
{ }:是以预编译的形式,将参数设置到sql语句中;PrepareStatement;
- ${ }:取出的值,直接拼装在sql语句上;会有sql注入的风险
- 大多情况下都应该使用 #{ }
- 原生jdbc支持占位符,在分表操作时按照年份分表拆分:select * from ${year}_salary
5.select 查询返回 List
- 创建方法接口:public List
getAllDiary(); 在sql文件中创建sql语句
<select id="getAllDiary" result="Diary"> select * from diary </select>
- mybatis会自动将对象封装到List中
[...]Docker容器 -2021Dubbo框架 -2020Git版本控制-20180Golang语言入门-2021Java设计模式-2019JVM探究-2019Mybatis框架-2019MySQL数据库-2019Netty网络编程框架-2021Redis数据库-2020SMS框架整合-2019Spring框架-2018Springboot框架-2019Springmvc框架-2019SVN版本控制-[...]