Mybatis9.28
1、简介
1.1、什么是Mybatis
1.2、持久化
1.3、持久层
1.4、为什么需要Mybatis?
2、第一个Mybatis程序
2.1、搭建数据库
2.2、创建一个模板
<!--导入依赖--> <dependencies> <!--MySQL驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency>
</dependencies>
核心配置文件
<?xml version="1.0" encoding="UTF8" ?> <!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.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <!--每一个Mapper.xml都需要在Mybatis配置文件中注册--> <mappers> <mapper resource="com/kuang/dao/UserMapper.xml"/> </mappers> </configuration>
//连接数据库,配置文件,返回会话工厂 public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory =null; static { //使用Mybatishuo获取SqlSessionFactory对象 String resource = "mybatis-config.xml"; //获得配置文件,读入sqlSessionFactory(sql会话工厂) try { InputStream inputStream = null; inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了SqlSessionFactory,顾名思义,我们就可以获得SqlSession的实例了 //SqlSession 完全包含了面向数据库执行Sql命令所需要的方法 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); } }
2.3、编写代码
1、实现类
//实体类 public class User { private int id; private String name; private String pwd; get(),set(),无参,有参 }
2、Dao接口
public interface UserDao { List<User> getUserList(); }
3、接口实现类Mapper配置文件
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace--> <mapper namespace="com.kuang.dao.UserDao"> <!--select查询语句--> <!--resultType返回集合到=User--> <select id="getUserList" resultType="com.kuang.pojo.User"> select * from mybatis.user </select> </mapper>
4、在核心配置文件中注册好配置文件:
<mappers> <mapper resource="com/kuang/dao/UserMapper.xml"/> </mappers>
2.4、测试
注意:
由于写的配置文件在java目录下,可能存在导不出配置文件,可在pom.xml中设置
<!--在build中配置resources,来防止我们资源导出失败问题。pom.xml中放置--> <!--系统是默认resource下读取,不用配置,如果文件不是放在resource中则要配置下面属性--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <!--java目录下的配置文件也要能被扫描--> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
如果是报错:
配置文件没有在核心配置文件注册
<!--每一个Mapper.xml都需要在Mybatis配置文件中注册--> <mappers> <mapper resource="com/kuang/dao/UserMapper.xml"/> </mappers> <!--每一个Mapper.xml都需要在Mybatis配置文件中注册--> <!--select查询语句--> <!--resultType返回集合到=User-->
测试类:
public class UserDaoTest { @Test public void test(){ //第一步:获得SqlSession会话对象 SqlSession sqlSession = MybatisUtils.getSqlSession(); //方式一:getMapper UserDao userdao = sqlSession.getMapper(UserDao.class); List<User> userList = userdao.getUserList(); //方式二:不安全,或被淘汰 //List<User> userList = sqlSession.selectList("com.kuang.dao.UserDao.getUserList"); for (User user : userList) { System.out.println(user); } //关闭sqlSession sqlSession.close(); }
结果
3、CRUP
1、namespace:
2、查select
UserMapper:
//根据ID查询用户 User getUserById(int id);
UserMapper.xml
<!--根据id查询语句--> <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User"> select * from mybatis.user where id = #{id} </select>
测试:
//根据Id查找用户 @Test public void getUserById(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1);//传入ID为1,查询 System.out.println(user); sqlSession.close(); }
结果:
3、增Insert
<!--添加用户--> <insert id="addUser" parameterType="com.kuang.pojo.User"> insert into mybatis.user (id ,name ,pwd) values (#{id},#{name},#{pwd}) </insert>
4、改update
<!--修改用户--> <update id="updateUser" parameterType="com.kuang.pojo.User"> update mybatis.user set name=#{name},pwd=#{pwd} where id = #{id}; </update>
5、删delete
<!--删除用户--> <update id="deleteUser" parameterType="int"> delete from mybatis.user where id = #{id}; </update>
6、万能的Map
UserMapper
//万能的Map int addUser2(Map<String,Object> map);
UserMapper.xml
<!--map添加用户--> <insert id="addUser2" parameterType="map"> insert into mybatis.user (id ,name ,pwd) values (#{userid},#{username},#{userpwd}) </insert>
测试:
//万能的map添加测试 @Test public void addUser2(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); Map<String, Object> map = new HashMap<String,Object>(); map.put("username","Hello"); map.put("userid",6); map.put("userpwd","23333333"); mapper.addUser2(map);//区别 sqlSession.commit(); sqlSession.close(); }
7、注意
<!--parameterType参数类型-->
<!--有返回值设置resultType类型-->
<!--#{id}在方法中取id-->
增删改需要提交事务,切记!!!!
防止SQL注入
8、模糊查询的写法:
4、配置解析
1、核心配置文件
2、环境配置(environments)
多个环境
事务管理:
数据源:
UNPOOLED没有池子,用完就关闭
POOLED有池子,等待超过时间关闭
注意:
标签都要规定顺序
3、属性(properties)
动态修改:
编写配置文件
db.properties:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8 username=root password=123456
核心配置文件引入:(可以在properties标签内增加一些属性,但重名优先会使用外部配置文件)
<?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--引入外部配置文件--> <properties resource="db.properties"> <!--也可以在里面添加一些属性,但优先使用外部配置文件--> <property name="username" value="root"/> </properties> <environments default="two"> <environment id="two"> <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="com/kuang/dao/UserMapper.xml"/> </mappers> </configuration>
4、类型别名(typeAliases)
1、直接给类起别名
设置别名:
别名引用:
2、扫描包,包下文件别名
引用:
通过注解起别名:(扫描包的情况下)
5、设置
6、其他配置:
<settings> <!--是否开启自动驼峰命名规则(camel case)映射--> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings>
7、映射器(mappers)
方式二和方式三
8、生命周期和作用域
image-20210606214732155
5、解决属性名和字段名不一致的问题
1、问题
2、解决方法:
1、别名
2、resultMap标签
6、日志:
6.1、日志工厂
6.2、Log4j
image-20210606225105885
image-20210606223549190
测试:
7、分页
1、Limit分页
结果:
2、RowBounds分页
3、分页插件
https://pagehelper.github.io/docs/
8、使用注解开发
8.1、面向接口编程
8.2、使用注解开发
详情:
8.3、CRUD
public interface UserMapper { //使用注解查询用户 @Select("select * from user") List<User> getUsers(); //方法存在多个参数,所有的参数面前必须加上@Param("id")注解 @Select("select * from user where id = #{id}") User getUserByID(@Param("id") int id); //插入用户 @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})") int addUser(User user); //根据ID修改名字和密码 @Update("update user set name=#{name},pwd=#{pwd} where id = #{id}") int updateUser(User user); //根据ID删除用户 @Delete("delete from user where id = #{id}") int deleteUser (@Param("id") int id); }
#{} 和 ${}的区别:
#{}防止SQL注入【安全】
${}不能防止SQL注入【不安全】
9、Lombok
(实体类偷懒的注解)
官网:https://projectlombok.org/
依赖:https://mvnrepository.com/artifact/org.projectlombok/lombok
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.10</version> </dependency>
总:
常用:
10、多对一处理
多对一:多个学生对应一个老师
环境搭建
老师学生表;
一个老师对应多个学生,通过tid相关
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`), key `fktid` (`tid`), constraint `fktid` foreign key (`tid`) references `teacher` (`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‘);
按照查询嵌套处理
查学生表后再查教师表(2SQL)
<!--思路: 1、查询所有的学生信息 2、根据查询出来的学生tid,寻找对应的老师 --> <select id="getStudent" resultMap="StudentTeacher"> select * from student </select> <resultMap id="StudentTeacher" type="com.kuang.pojo.Student"> <result property="id" column="id"/> <result property="name" column="name"/> <!--复杂的属性,我们需要单独处理,对象:association标签集合:collection标签--> <association property="teacher" column="tid" javaType="com.kuang.pojo.Teacher" select="getTeacher"/> </resultMap> <select id="getTeacher" resultType="com.kuang.pojo.Teacher"> select * from teacher where id = #{id} </select>
按照结果嵌套处理
直接从数据库SQL语句查两表,返回值需要做处理。
<!--方式二:按照结果嵌套--> <select id="getStudent2" 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="com.kuang.pojo.Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <association property="teacher" javaType="com.kuang.pojo.Teacher"> <result property="name" column="tname"/> </association> </resultMap>
11、一对多处理
一个老师对应多个学生
环境搭建:
按照结果嵌套处理
<!--按结果嵌套查询--> <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 = #{tid} </select> <resultMap id="TeacherStudent" type="com.kuang.pojo.Teacher"> <result property="id" column="tid"/> <result property="name" column="tname"/> <!--复杂的属性,我们需要单独处理,对象:assciation标签集合:collection标签 javaType="" 指定属性的类型 集合中的泛型信息,我们使用ofType获取--> <collection property="students" ofType="com.kuang.pojo.Student"> <result property="id" column="sid"/> <result property="name" column="sname"/> <result property="tid" column="tid"/> </collection> </resultMap>
按照查询嵌套处理
<!--按照查询嵌套处理--> <select id="getTeacher2" resultMap="TeacherStudent2"> select * from mybatis.teacher where id = #{tid}; </select> <resultMap id="TeacherStudent2" type="com.kuang.pojo.Teacher"> <!--1.对象:students 2.java类型:数组 3.属于类型:学生实体类 4.子查询:getStudentByTeacherId方法 5.传递:id--> <collection property="students" javaType="ArrayList" ofType="com.kuang.pojo.Student" select="getStudentByTeacherId" column="id"/> </resultMap> <select id="getStudentByTeacherId" resultType="com.kuang.pojo.Student"> select * from mybatis.student where tid = #{tid} </select> </mapper>
小结
12、动态SQL
搭建环境:
CREATE TABLE `blog`( `id` varchar(50) NOT NULL COMMENT ‘博客id‘, `title` varchar(100) NOT NULL COMMENT ‘博客标题‘, `author` varchar(30) NOT NULL COMMENT ‘博客作者‘, `create_time` datetime NOT NULL COMMENT ‘创建时间‘, `views` int(30) NOT NULL COMMENT ‘浏览量‘ )ENGINE = Innodb DEFAULT CHARSET = utf8
@Data public class Blog { private int id; private String title; private String author; private Date createTime; private int views; }
IF
choose(when,otherwise)多选一
<select id="queryBlogChoose" parameterType="Map" resultType="Blog"> select * from mybatis.blog <where> <choose> <when test="title!=null"> title = #{title} </when> <when test="author!=null"> and author = #{author} </when> <otherwise> and views = #{views} </otherwise> </choose> </where> </select>
像java中的switch语句
trim(where,set)
where
包裹中,去掉多余的and和or语句
在where中避免直接加and导致where and 语句错误!
set
去掉动态修改数据库时,多出来的 ,号
sql片段(引用):
foreach
强大,较难理解!
13、缓存
1、简介
2、mybatis缓存
3、一级缓存
缓存失效的情况:
4、二级缓存
步骤:
(在核心配置文件中)
解决:
5、缓存原理:
6、自定义缓存
https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache/1.1.0
有配置文件需下载