MyBatis 是一款优秀的持久层框架,用于简化 JDBC 开发。
1.持久层:
负责将数据到保存到数据库的那一层代码
JavaEE三层架构:表现层、业务层、持久层
2.框架:
①框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型;
②在框架的基础之上构建软件编写更加高效、规范、通用、可扩展。
MyBatis配置环境
第一步:新建模块,
第二步:导jar包,,点进pom.xml文件中,jar包文件
注意在的下面jar包(因为xml文件有约束),pom依赖坐标.xml,把文件复制粘贴到里面,点击刷新,
jar包生成在了这里。
第三步:复制logback.xml到中。
第四步:在java下创建mapper和pojo包,根据数据库中的字段名在pojo包下 编写类(成员属性:日期是这个类型————)。
第五步:将文件mybatis-config.xml复制到,并且修改参数 ,固定修改 注意图中day18为MySQL中的数据库名,写接口映射文件位 置,为“XXXMapper.xml”—XXX给类名。
第六步:在mapper包下编写接口。
第七步:将xxxMapper.xmlXXXMapper.xml文件复制到 中,XXX改 为”类名Mapper.xml”,修改XXXMapper.xml文件中的 的参数,包名.接口 名为:,写方法名,方法返回值类型为: ,编写SQL语句,
修改之后变成:。
第八步:编写测试类,在pojo包下创建,
前三行为固定:1.String resource = “mybatis-config.xml”;
2.InputStream inputStream = Resources.getResourceAsStream(resource);
3.SqlSessionFactory sqlSessionFactory =new SqlSessionFactoryBuilder().build(inputStream);
MyBatis 核心配置文件(对配置环境进行优化)
typeAliases标签:给包.类起别名,让类使用更简单。
mapper标签:加载接口映射文件。
在mybatis-config.xml文件中:
<typeAliases>
<!--typeAlias:给实体类取别名 type:包名.类名 alias:别名,一般别名就是类名,别名在使用时不区分大小写-->
<!--<typeAlias type="com.itheima.pojo.User" alias="User"/>
<typeAlias type="com.itheima.pojo.Employee" alias="Employee"/>
<typeAlias type="com.itheima.pojo.Dog" alias="Dog"/>-->
<!--每个实体类都配置一个别名,太麻烦了,
有简单的方案package:包扫描,扫描一个包中所有实体类,并且别名就是类名name:包名-->
<package name="com.itheima.pojo"/>
</typeAliases>
注意:typeAliases要放在配置environments的前面(XML文件有约束)
<mappers>
<!--告诉MyBatis接口中对应的SQL语句在这个文件中-->
<!--<mapper resource="UserMapper.xml"/>
<mapper resource="DogMapper.xml"/>
<mapper resource="EmployeeMapper.xml"/>-->
<!--mapper:只能指定一个映射文件的位置,不方便,有更好的方案-->
<!--package:包扫描,扫描这个包中所有的接口和映射文件name:包名,写接口所在的包名
需要两个前提:
1.接口名和接口的映射文件名要一样
2.接口名接口名和接口的映射文件编译后要在同一个包中-->
<mapper resource="com.itheima.mapper"/>
</mappers>
注意:mappers要放在配置environments的后面(XML文件有约束)
MyBatis增删改查
基本增删改查
①在接口中添加方法:
②在接口映射文件UserMapper.xml配置SQL语句:
③执行方法:
@Test
public void test01() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);//自动提交事务
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//通过id查询用户
User user = mapper.selectById(1);
System.out.println(user);
//sqlSession.commit();手动添加事务
sqlSession.close();//关闭资源
}
<!-- update:配置修改的SQL语句
参数是自定义对象:#{成员变量名},先使用?占位,取出参数成员变量值给?赋值
username=#{username}: username是表中的字段名,#{username}先使用?占位,取出参数成员变量给?赋值-->
<update id="update">
UPDATE user
<set>
<if test="username!=null and username!=''">
username=#{username},
</if>
<if test="birthday!=null">//只有字符串才需要判断是否为空
birthday=#{birthday},
</if>
<if test="sex!=null and sex!=''">
sex=#{sex},
</if>
<if test="address!=null and address!=''">
address=#{address}
</if>
</set>
WHERE id=#{id};
</update>
<!-- delete:配置删除的SQL语句
注意增删改不需要配置reslutType:增删改的返回值都是影响的行数-->
<delete id="deleteBuId">
DELETE FROM user WHERE id=#{uid}
</delete>
<!--insert:配置插入的SQL语句
参数是自定义对象:#{成员变量名}
useGeneratedKeys:要得到自增的主键
keyProperty="id":类中的id成员变量保存自增的主键
-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user VALUES (NULL,#{username},#{birthday},#{sex},#{address});
</insert>
useGeneratedKeys:要得到自增的主键
keyProperty=”id”:类中的id成员变量保存自增的主键
映射配置文件小结:
当多参数查询时
(起别名)<br />**参数接收三种方法:**①散装参数: 如果方法中有多个参数,需要使用@Param("SQL参数占位符名称")<br /> ②对象参数: 对象的属性名称要和参数占位符名称一致<br /> ③Map集合参数: Map的键要和占位符名称一致<br />在写接口时:
//批量删除
void deleteByIds(@Param("ids")int[] ids);//int [] ids={1,4}
//根据用户名和性别查询用户(多参数处理)
//方案1:给多个参数设置@Param("名字")注解,在SQL语句中#{名字}
//List<User> selectByCondition(@Param("username")String username,@Param("sex") String sex);
//方案2:使用自定义对象保存多个数据
//List<User> selectByCondition(User user);
//方案3:使用Map集合保存多个数据,在SQL语句中#{键}取出值
List<User> selectByCondition(Map<String,String> map);
在测试类中:
@Test
public void test05() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession(true);//自动提交事务
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//方案1
//List<User> users = mapper.selectByCondition("%精%", "女");
//方案2
/*
User u = new User();
u.setUsername("%精%");
u.setSex("女");
List<User> users = mapper.selectByCondition(u);
*/
//方案3
HashMap<String, String> map = new HashMap<>();
map.put("username","");
map.put("sex","妖");//null:对象为null(你没有女朋友) "":空字符串,没有内容的字符串(你有女朋友,但没有灵魂)
List<User> users = mapper.selectByCondition(map);
users.forEach(System.out::println);
//sqlSession.commit();手动添加事务
sqlSession.close();
动态SQL
1.if: 如果条件为true, 拼接里面的SQL。
2.where: 相当于WHERE关键字, 会去掉多余的 AND OR。
3.set: 用在update语句中,相当于set关键字;去掉SQL代码片段中后面多余的逗号。
4.foreach: 遍历数组或集合, 相当于Java中的增强for。
(在上面下面代码中有体现)
<!--根据用户名和性别查询用户(多参数处理)
if标签的test属性里面直接写名字,不需要写#{名字}-->
<select id="selectByCondition" resultType="com.itheima.pojo.User">
SELECT * FROM user
<where>
<if test="username!=null and username!=''">//这里的and不能是AND大写
username LIKE #{username}
</if>
<if test="sex!=null and sex!=''">
AND sex=#{sex};
</if>
</where>
</select>
<delete id="deleteByIds">
DELETE FROM USER WHERE id IN
<!-- 我们要遍历的内容:(1,4);
foreach:遍历数组或集合
collection:要遍历的数组或集合,在UserMapper.java中@Param(别名)起别名
item:要遍历出的元素,名字自定义
open:遍历前添加的内容
separator:分隔符,在元素之间添加的内容
close:遍历结束添加的内容
-->
<foreach collection="ids" item="id" open="(" separator="," close=");">
#{id}
</foreach>
</delete>
sql和include标签(了解)
resultMap输出映射(查询结果的字段名称和类的成员变量名不一致时)
两种方法解决:
①在核心配置文件中使用settings设置mapUnderscoreToCamelCase为true将映射下划线为驼峰 命名法。(核心配置文件在MyBatis官网中找复制粘贴到映射配置文件”XXXMapper.xml”中,注意要把false改成true!)
②使用resultMap解决:resultMap可以建立查询的列与对象属性的对应关系。
MyBatis多表查询
MyBatis的工具类,简化MyBatis代码:
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
// 这是MyBatis的工具类,简化MyBatis代码
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
// 我们只需要一个SqlSessionFactory,在静态代码块中创建SqlSessionFactory
static {
try {
// 编写代码让MyBatis跑起来,执行SQL语句
String resource = "mybatis-config.xml";
// 加载核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
// 得到SqlSession工厂,赋值给成员变量
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
// 返回SqlSessionFactory
public static SqlSessionFactory getSqlSessionFactory() {
return sqlSessionFactory;
}
// 返回SqlSession,不带事务的
public static SqlSession openSession() {
return sqlSessionFactory.openSession();
}
//开启自动提交事务
public static SqlSession openSession(boolean autoCommit) {
return sqlSessionFactory.openSession(autoCommit);
}
}
一对一关联
第一步:创建实体类,在实体类中
当添加了时,记得重新生成getset方法。(注意区分数据类型UserInfo和变量名userInfo)
第二步:编写接口,返回值为User,包含 了User和UserInfo的数据。
第三步:在XXXMapper.xml中编写SQL语句
注:
1.resultType: 自动映射,表中的字段和类中的成员变量一样的才有数据
2.resultMap: 结果映射,处理表中字段和类中成员变量不一样的.手动指定对应关系.多表查询必须要用 resultMap
3.多表查询表中字段名和类中成员变量一样的也要指定, 如果指定autoMapping=”true”就可以不用写,主键一定要写
4.id: 名字,随便取,后面要使用
5.type: 数据保存到这个类的对象中
一对多查询
第一步:创建实体类
第二步:编写接口
第三步:在XXXMapper.xml中编写SQL语句
第四步:编写测试类
多对多查询
两个一对多
下面例题为三表查询:
1.
2.
3.
4.
5.
注意:两个一对多之间的实体类都重写了toString方法,可能会出现一直互相打印的情况(递归),所以要删除一个实体类的toString方法。
在一对多或多对多的ofType和javaType使用情境
你去看看无论是collection标签还是association标签里面都需要写property这个标签吧?找到collection标签还是association标签所在的xml文件对应的实体类中property标签的值是什么类型的?如果是集合如图一,就用ofType,并且ofType的值是集合中存储元素的类型。如果不是集合如图二,就用javaType,并且javaType的值是实体类中属性的类型。
ofType:
①根据property标签所在xml文件,对应到实体类User文件,找到property标签的值。
②发现property标签的值accounts在User文件中的类型是泛型为Account的List集合。
③因为是集合,所以选择使用ofType标签(写成集合是因为两个表之间是一对多或者多对多关系,我这里是一个用户可以拥有多个账户,一对多关系)。
④集合中存储的元素类型是Account类型,所以ofType的值是account。
JavaType:
MyBatis注解开发
MyBatis缓存
MyBatis批量插入
@Test
public void test08() {
// 记录开始时间
long start = System.currentTimeMillis(); // MyBatis批量插入
SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession(ExecutorType.BATCH);
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
for (int i = 0; i < 10000; i++) {
User user = new User(0, "黑熊精"+i, Date.valueOf("1999-09-09"), "妖", "普陀山");
mapper.add(user);
}
sqlSession.commit();//提交事务
sqlSession.close();
// 记录结束时间
long end = System.currentTimeMillis();
// 消耗时间 = 结束时间 - 开始时间
System.out.println("消耗时间: " + (end - start));
}
}
SqlSession sqlSession = MyBatisUtils.getSqlSessionFactory().openSession(ExecutorType.BATCH);
// MyBatis批量插入
批量插入只提交了一个事务,多个事务时是影响性能的。