一、第一个mybatis程序
思路流程:搭建环境–>导入Mybatis—>编写代码—>测试
1.搭建实验数据库mybatis,新建一张usr表
2.在pom.xml导入依赖
<dependencies>
<!--mybatis相关-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql相关-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
</dependencies>
<!--配置Maven静态资源过滤问题-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
2.写对应数据库的实体类com.tong.pojo包下的User
@Data
public class User {
private int id; //id
private String name; //姓名
private String pwd; //密码
}
3.创建包com.tong.dao中写UserMapper的接口
public interface UserMapper {
//查询所有
public List<User> selectUser();
}
4.在com.tong.dao下写对应的UserMapper.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="com.tong.dao.UserMapper">
<select id="selectUser" resultType="com.tong.pojo.User">
select * from user
</select>
</mapper>
5.在resources目录下新建mybatis-config.xml配置文件,编写mybatis的配置
<?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>
<!--自定义别名,这样在mapper.xml中的这样写resultType="Student
如果没有自定义别名,在mapper.xml 中要写完包名 resultType="com.kuang.pojo.Student
-->
<typeAliases>
<package name="com.tong.pojo" />
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!--注册映射文件 1-->
<!-- <mappers>
<mapper class="com.tong.dao.UserMapper"/>
</mappers>-->
<!--注册映射文件 2-->
<mappers>
<mapper resource="com/tong/dao/UserMapper.xml"/>
</mappers>
</configuration>
6.写一个测试类
@Test
public void test() throws IOException {
//读取mybaits的配置文件
String resource = "mybatis-config.xml";
InputStream in =Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(in);
//获得SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
//获得对应的类
StudentMapper mapper = sqlSession.getMapper(UserMapper.class);
//执行的方法
List<User> users = mapper.selectUser();
users.forEach(System.out::println);
}
二、mybatis执行流程
执行流程:idea要打断点通过debug方式启动才看得到
1.Resources加载mybaits.xml的配置文件------>
2.实例化SqlSessionFactoryBuilder().build()------>
3.XMLConfigBuilder 解析mybatis.xml里面的配置 ------>
4.把配置信息存放到Configuration中------>
5.实例化SqlSessionFactory------>
6.由TransactionFactory创建一个Transaction事务对象------>
7.创建执行器Excutor------>
8.创建SqlSession接口------>
9.实现CRUD,如果执行成功就提交事务,失败就回滚到Transaction------>关闭
三、mybatis在插入语句中使用返回的主键-
<insert id="addOrder" parameterType="OrderList" useGeneratedKeys="true" keyProperty="order_id" keyColumn="id">
//在service中这样获取
public void addOrder(OrderList orderList) {
int i = trainTicketOrderDao.addOrder(orderList);
System.out.println("返回的条数i:"+i);
System.out.println("返回的主键:"+orderList.getOrder_id());
}
四、mybatis中使用log4j日志
1.导入log4j的依赖
<!--日志-->
<dependency>
<groupId>slog4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2.在resources目录中创建log4j.properties,并添加内容
##通过配置只查看com.kuang的namespace下的sql语句的日子
log4j.logger.com.kuang.dao=debug,console
#控制台附加器
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern= [%-5p][%d{yyyy-MM-dd HH:mm:ss}]%m%n
3.在mybatis-config.xml中添加属性,要注意按顺序
<!--要注意按顺序-->
<settings >
<setting name="logImpl" value="LOG4J" />
</settings>
五、MyBatis缓存
-
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
-
默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
-
二级缓存需要手动开启和配置,他是基于namespace级别的缓存
1.一级缓存
-
一级缓存只存在一个SqlSession里面,并且只有查询的时候才生效,session.close()的时候失效
-
一级缓存失效的四种情况
- 一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它
- 增删改都会是刷新缓存
2.二级缓存
- 开启二级缓存的步骤
- 开启全局缓存 【mybatis-config.xml】
<setting name="cacheEnabled" value="true"/>
2.在需要开启二级缓存的xxxMapper.xml中添加
<cache/>
<!--也可以这样配置-->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
<!--这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的
512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者
产生冲突。-->
注意:如果要使用二级缓存,实体类要序列号,不然会报错
3.缓存的执行顺序
用户-------->二级缓存-------->一级缓存-------->数据库
六、使用万能Map
在字段比较多的时候用map非常方便
-
接口中
//万能的map int addUser(Map<String, Object> map);
-
xml中
<!--用map类型,对象的属性可以直接取出来,传递map的key,
values后面可自定义名字,无需完全匹配数据库,对应参数中map的key
-->
<insert id="addUser" parameterType="map">
insert into mybatis.user (id,name,password) values (#{id},#{username},#{password});
</insert>
- 测试
//添加
@Test
public void addUser1() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("username", "马云");
map.put("password", "666666");
mapper.addUser(map);
sqlSession.commit();//提交事务
sqlSession.close();//关闭连接
}
七、使用foreach一次性插入批量数据
可以使用list,也可以使用map:
方式一:使用list
方式二:使用map
- 接口中
//方式一:list
//批量添加
int insertUser_piliang(List<Map<String,Object>> list);
//方式二:map
//批量添加
int insertUser_piliang2(Map map);
- mapper.xml中
<!-- 方式一:list -->
<insert id="insertUser_piliang" parameterType="java.util.List">
insert into user(name,pwd) values
<foreach collection="list" index="index" item="item" separator=",">
(#{item.name},#{item.pwd})
</foreach>
</insert>
<!-- 方式二:map -->
<insert id="insertUser_piliang2" parameterType="map">
insert into user(name,pwd) values
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
-->
<foreach collection="list" index="index" item="item" separator=",">
(#{item.name},#{item.pwd})
</foreach>
</insert>
- 测试
//方式一:list
@Test
public void insertUser_piliang(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
ArrayList<Map<String,Object>> list = new ArrayList<>();
HashMap<String, Object> map = new HashMap<>();
for (int i = 0; i < 10; i++) {
map.put("name", "邓紫棋");
map.put("pwd", "666666");
list.add(map);
}
mapper.insertUser_piliang(list);
sqlSession.commit();
sqlSession.close();
}
//方式二:map
@Test
public void insertUser_piliang2(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String,Object> map = new HashMap<>();
List<User> list = new ArrayList<>();
User user = new User();
//用for循环遍历添加100个User
for (int i = 0; i < 100; i++) {
user.setName("马云");
user.setPwd("888888");
list.add(user);
}
map.put("list", list);
mapper.insertUser_piliang2(map);
sqlSession.commit();//手动提交事务
sqlSession.close();
}
八、动态Sql
if语句
需求:根据用户名和密码查询,如果用户名为空,就根据密码查询,反之,密码为空,则根据用户名查询
- 接口
List<User> queryUserIf(Map map);
- xml
<select id="queryUserIf" parameterType="map" resultType="User">
select * from user
<where>
<if test="name != null">
name=#{name}
</if>
<if test="pwd != null">
and pwd=#{pwd}
</if>
</where>
</select>
这个 标签会知道如果它包含的标签中有返回值的话,它就插入一个 。此外,如果标签返
回的内容是以AND 或OR 开头的,则它会剔除掉。就是当name 的值为空时,会剔除掉and,有些案例直接用1=1
替换掉 ,但这是不安全的,存在sql注入问题。
- 测试
//if查询
@Test
public void queryUser(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("name", "李四");
map.put("pwd", "888888");
List<User> users = mapper.queryUserIf(map);
users.forEach(System.out::println);
}
set语句同 if 一样的原理,不举列了
choose 语句
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose
标签可以解决此类问题,类似于 Java 的 switch 语句
- 接口
//choose
List<User> queryUserChoose(Map map);
- xml
<select id="queryUserChoose" resultType="User" parameterType="map">
select * from user
<where>
<choose>
<when test="name != null">
name=#{name}
</when>
<when test="pwd != null">
and pwd=#{pwd}
</when>
<otherwise>
and id=#{id}
</otherwise>
</choose>
</where>
</select>
- 测试
- 测试结果:如果map中都没有值时,以id为主,如果name中有值,就以name为主查询,不关pwd的事
//choose查询
@Test
public void queryUserChoose(){
SqlSession sqlSession = MyBatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("name", "张三");
map.put("pwd", "888888");
map.put("id",2); //这是固定的,一定要有这个值
List<User> users = mapper.queryUserChoose(map);
users.forEach(System.out::println);
}
模糊查询 like
转载csdn:https://blog.csdn.net/Crystalqy/article/details/79419244
常用的模糊查询有三种方法:**
- 直接使用 % 拼接字符串,如
'%'#{name}'%'
或"%"#{name}"%"
,单引号或双引号都可以。 - 使用concat(str1,str2)函数拼接
- 使用mybatis的bind标签
<!-- ******************** 模糊查询的常用的3种方式:********************* -->
<select id="getUsersByFuzzyQuery" parameterType="User" resultType="User">
select * from users
<where>
<!--
方法一: 直接使用 % 拼接字符串
注意:此处不能写成 "%#{name}%" ,#{name}就成了字符串的一部分,
会发生这样一个异常: The error occurred while setting parameters,
应该写成: "%"#{name}"%",即#{name}是一个整体,前后加上%
-->
<if test="name != null">
name like "%"#{name}"%"
</if>
<!--方法二: 使用concat(str1,str2)函数将两个参数连接 -->
<if test="phone != null">
and phone like concat(concat('%',#{phone}),'%')
</if>
<!--方法三: 使用 bind 标签,对字符串进行绑定,然后对绑定后的字符串使用 like 关键字进行模糊查询 -->
<if test="email != null">
<bind name="pattern" value="'%'+email+'%'"/>
and email like #{pattern}
</if>
</where>
</select>
九、多对一(以多方为主)
需求:查询学生的名字以及对应的老师的名字
多对一的理解:
- 多个学生对应一个老师
数据库设计
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO teacher(`id`, `name`) VALUES (1, '潘老师');
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', 1);
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', 1);
实体类
@Data //GET,SET,ToString,有参,无参构造
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
//多个学生可以是同一个老师,即多对一
private Teacher teacher;
}
按结果嵌套处理(这种方式比较简单)
1.接口方法编写
public List<Student> getStudents2();
2.编写对应的mapper文件
<!--
按查询结果嵌套处理
思路:
1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
select s.id sid, s.name sname , t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<id property="id" column="sid"/>
<result property="name" column="sname"/>
<!--关联对象property 关联对象在Student实体类中的属性-->
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
测试
@Test
public void testGetStudents2(){
SqlSession session = MybatisUtils.getSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> students = mapper.getStudents2();
for (Student student : students){
System.out.println(
"学生名:"+ student.getName()
+"\t老师:"+student.getTeacher().getName());
}
}
十、一对多(以一方为主)
需求:获取指定老师,及老师下的所有学生
一对多的理解:
- 一个老师拥有多个学生
按结果嵌套处理(推荐方式)
TeacherMapper接口编写方法
//获取指定老师,及老师下的所有学生
public Teacher getTeacher(int id);
编写接口对应的Mapper配置文件
<mapper namespace="com.tong.mapper.TeacherMapper">
<!--
思路:
1. 从学生表和老师表中查出学生id,学生姓名,老师姓名
2. 对查询出来的操作做结果集映射
1. 集合的话,使用collection!
JavaType和ofType都是用来指定对象类型的
JavaType是用来指定pojo中属性的类型
ofType指定的是映射到list集合属性中pojo的类型。
-->
<select id="getTeacher" resultMap="TeacherStudent">
select s.id sid, s.name sname , t.name tname, t.id tid
from student s,teacher t
where s.tid = t.id and t.id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="name" column="tname"/>
<collection property="students" ofType="Student">
<result property="id" column="sid" />
<result property="name" column="sname" />
<result property="tid" column="tid" />
</collection>
</resultMap>
</mapper>
测试
@Test
public void testGetTeacher(){
SqlSession session = MybatisUtils.getSession();
TeacherMapper mapper = session.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher(1);
System.out.println(teacher.getName());
System.out.println(teacher.getStudents());
}
总结:
-
使用mybatis时,增删改查都需要提交事务,否则运行成功并没有添加到数据库
-
可以手动提交事务,也可以在openSession()是设置为true,此时不用每次都手动提交了
-
这是在自定义的MybatisUtil工具包中
//获取SqlSession连接 public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(true);//设置为true }
-