MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
安装
如果是用maven项目的话只需要把下面的 dependency 代码置于 pom.xml 文件中:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
对数据库的操作
1.查询
重点看一下查询
创建一个接口
Student是一个封装类,(注意的是 属性名最好与数据库字段名一一对应,去掉一些麻烦)
public interface StudentDao{
List<Student> queryALl();
}
然后配置StudentMapper.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">
<!-- 上面是xml头文件-->
<!-- namespace对应空Dao接口的全名 -->
<mapper namespace="com.aaa.mybatis.dao.StudentDao">
<!-- 此处的id是查询语句的名称,对应接口中的方法名 -->
<select id="queryAll" resultType="Student">
select * from student;
</select>
这时需要把这个映射好的xml文件配置到配置文件mybatis_conf.xml文件中
<mappers>
<mapper class="com.aaa.mybatis.dao.StudentDao" />
<mapper resource="mapper/StudentMapper.xml" />
</mappers>
然后再main方法中测试一下
// 1. 读入配置文件
String confPath = "mybatis_con.xml";
InputStream in = Resources.getResourceAsStream(confPath);
// 2. 构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);
// 3. 获取sqlSession对象(用于具体的CRUD)
SqlSession sqlSession = sessionFactory.openSession();
StudentDao studentDao = sqlSession.getMapper(StudentDao.class);
List<Student> studentList = studentDao.queryAll();
log.info("studentList: " + studentList);
这里就是查询如果要根据哪个字段查询的时候在StudentMapper.xml这样配置
这里条件用#{}写法
<select id="queryById" parameterType="int" resultType="Student">
select * from teacher where id = #{id};
</select>
,这里是一个字段的,由于这个编译机制,不会把属性名编译进去,是按照类型来识别的当只有一个字段的时候这样写不会出现什么问题
public interface StudentDao{
Student queryById(int id);
}
但如果是两个字段是不可以这样写的
这里给出的解决方式是这样的,也有其他的这里只介绍这一种
是小于号,因为<这个在xml中是关键符号
<select id="queryByIdAndAge" resultType="Student">
select * from teacher where id = #{id} and age <= #{age};
</select>
注意的是@param()里面的值是与#{}这里的值是对应的
public interface StudentDao{
List queryByIdAndAge(@Param(“id”) int id, @Param(“age”) int age);
}
2.添加
前面都是差不多的就是需要在StudentMapper.xml配置一个插入语句
<insert id="insertTeacher" parameterType="Teacher">
insert into teacher(tname) values (#{tname});
</insert>
public interface StudentDao{
int insertTeacher(Teacher teacher);
}
查询会写了剩下的应该都可以举一反三,加油.主要就是sql语句的区别
当然注意一下,添加,修改,删除的返回值都是int类型的,因为返回的是影响了几条数据
动态sql:
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
where ,if 的用法
当用多个字段限制的时候,就像下面这样写多个if语句
<select id="queryStudentByCondition" resultType="Student">
select * from student
<where>
<if test="sname != null">
sname = #{sname}
</if>
<if test="nickName != null">
and nick_name = #{nickName}
</if>
<if test="id != null">
and id = #{id}
</if>
</where>
</select>
choose, when, otherwise
有时我们不想应用到所有的条件语句,而只想从中择其一项。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
示例:
<select id="queryStudentByChooseWhen" resultType="Student">
select * from student
<where>
<choose>
<when test="sname != null">
and sname = #{sname}
</when>
<when test="nickName != null">
and nick_name = #{nickName}
</when>
<otherwise>
and id = 5
</otherwise>
</choose>
</where>
</select>
trim, where, set
当我们拼接动态SQL时,如果一个查询条件都没有,那我们就不需要where子句,而如果有至少一个条件我们就需要where子句。这样,我们就需要做个判断,而mybatis里的标签就省去了我们自己做这个判断。 使用示例:
<update id="updateById" parameterType="Student">
update student
<!--
<set>
-->
<trim prefix="set" suffixOverrides=",">
<if test="sname != null">
sname = #{sname},
</if>
<if test="nickName != null">
nick_name = #{nickName},
</if>
</trim>
<!--
</set>
-->
where id = #{id}
</update>
foreach
foreach标签用于通过循环的方式动态拼接SQL,使用方法如下:
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
WHERE ID in
<foreach item="item" index="index" collection="list"
open="(" separator="," close=")">
#{item}
</foreach>
</select>
item: 指定在循环中可以用的item属性名称。当循环的对象是List、Set、数组时item是当前迭代的对象的元素值;而当循环对象是Map时,item是key对应的值
index: 指定在循环中可以用的index属性名称。当循环的对象是List、Set、数组时index是当前迭代的次数;而当循环对象是Map时,index是key
建议看官方文档
批量插入
1.常规
1.常规方式的批量插入
sql语句
int bathNorm(List<Teacher> teacherList);
<insert id="bathNorm" parameterType="Teacher">
insert into teacher (tname,age) values
<foreach collection="list" item="teacher" separator="," close=";">
(#{teacher.tname},#{teacher.age})
</foreach>
</insert>
java代码
StudentDao studentDao=null;
String[] tnameArr = new String[]{"火", "水", "金", "木", "土"};
public void setup(){
teacherDao= MyBatisTools.getInstance().openSession().getMapper(TeacherDao.class);
Random random = new Random();
// 构造测试数据 插入一万条
for(int i = 0; i < 10000; i++) {
Teacher teacher = new Teacher();
int idx = random.nextInt(tnameArr.length);
teacher.setTname(tnameArr[idx] +"_"+ (i + 1));
teacher.setAge(i+1);
testData.add(teacher);
}
}
<?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>
<!-- 引入外部配置-->
<properties resource="jdbc.properties" />
<!-- 类型别名是为 Java 类型设置一个短的名字。 它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余-->
<typeAliases>
<typeAlias type="com.lanou3g.mybaties.bean.Teacher" alias="Teacher" />
<typeAlias type="com.lanou3g.mybaties.bean.Student" alias="Student"/>
</typeAliases>
<!-- 配置不同环境的参数 -->
<environments default="development">
<!-- 开发环境数据库、事务配置 -->
<environment id="development">
<!-- 事务管理使用JDBC的事务 -->
<transactionManager type="MANAGED"/>
<!-- 配置开发环境数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 注解方式 -->
<mapper resource="mapper/TeacherMapper.xml" />
</mappers>
</configuration>
配置的类
public class MyBatisTools {
private static ConcurrentHashMap<String, SqlSessionFactory> factoryMap = new MyConcurrentHashMap();
private static MyBatisTools myBatisTools;
private MyBatisTools() {}
public static MyBatisTools getInstance() {
if(myBatisTools == null) {
synchronized (MyBatisTools.class) {
if(myBatisTools == null) {
myBatisTools = new MyBatisTools();
}
}
}
log.debug("当前一共有: " + factoryMap.size() +"个SqlSessionFactory实例");
log.debug("他们分别是: " + factoryMap);
return myBatisTools;
}
public SqlSessionFactory getSessionFactory() {
return getSessionFactory(null);
}
public SqlSessionFactory getSessionFactory(String env) {
try {
// 1. 读入配置文件
InputStream in = Resources.getResourceAsStream("mybaties.xml");
// 2. 构建SqlSessionFactory(用于获取sqlSession)
SqlSessionFactory sessionFactory = null;
synchronized (factoryMap) {
if(factoryMap.containsKey(env)) {
return factoryMap.get(env);
} else {
sessionFactory = new SqlSessionFactoryBuilder().build(in, env);
factoryMap.put(env, sessionFactory);
}
}
return sessionFactory;
} catch (Exception e) {
log.error("初始化SqlSessionFactory失败", e);
return null;
}
}
public SqlSession openSession() {
return getSessionFactory(null).openSession();
}
public SqlSession openSession(boolean autoCommit) {
return getSessionFactory(null).openSession(autoCommit);
}
public SqlSession openSession(ExecutorType executorType, boolean autoCommit) {
return getSessionFactory(null).openSession(executorType, autoCommit);
}
}
/**
* 继承原生ConcurrentHashMap,处理null key问题
*/
class MyConcurrentHashMap extends ConcurrentHashMap {
@Override
public Object put(Object key, Object value) {
if(key == null) {
key = "null";
}
return super.put(key, value);
}
@Override
public boolean containsKey(Object key) {
if(key == null) {
key = "null";
}
return super.containsKey(key);
}
@Override
public Object get(Object key) {
if(key == null) {
key = "null";
}
return super.get(key);
}
}
teacher类
public class Teacher {
private Integer id;
private String tname;
private Integer age;
public Teacher() {
}
public Teacher(String tname) {
this.tname = tname;
}
@Override
public String toString() {
return "Teacher{" +
"id=" + id +
", tname='" + tname + '\'' +
", age=" + age +
"}\n";
}
}
这种方式比较快,但是数据库默认上传数据是4M,超过就要修改数据库的默认值,比较有局限
spring和mybatis整合
首先加一下依赖包,版本号自己选择适合的
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.1</version>
</dependency>
配置数据源
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
配置Spring、Mybatis整个的管理Bean
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 指定XML Mapper文件的路径 -->
<property name="mapperLocations" value="classpath:/mapper/*"/>
</bean>
通过mybatis scheme来自动扫描所有的Mapper接口
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring.xsd">
<!-- 自动扫描所有Mapper接口 -->
<mybatis:scan base-package="com.lanou3g.spring.mapper" />
</beans>
使用
public class Application {
public static void main(String[] args) throws SQLException {
// 1. 初始化IOC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. 从容器中获取Service对象(Mapper对象已经自动注入到Service中了)
MessageServiceImpl messageService = ctx.getBean(MessageServiceImpl.class);
// 3. 执行查询所有方法
List<Message> messageList = messageService.queryAll();
log.info("" + messageList);
}
}