MyBatis相关

tech2024-01-31  76

一、第一个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 }
最新回复(0)