MyBatis入门级了解

    技术2022-07-11  71

    1、MyBatis是什么

    ​ View ------ Controller ----- Service ----- DAO ------ 数据库

    jsp/HTML Servlet/SpringMVC Spring jdbc/dbutils/jdbctemplate/mybatis

    mybatis实际上就是 DAO层的一个解决方案

    学习过jdbc、dbutils、jdbcTemplate、Hibernate 那么为什么我们还要学习 mybatis呢

    JDBC:代码非常复杂、速度快

    Hibernate:代码精简、致命的缺点(速度慢)

    dbutils、jdbcTemplate:框架都不算 只是对jdbc的一个简单的封装而已

    mybatis:他是属于效率处于 JDBC和Hibernate之间

    ​ 他的代码的复杂度也是趋于 JDBC和Hibernate之间

    ​ 代码灵活、怎么写都是对的

    iBatis和mybatis之间的关系是什么?

    ibatis是以前的叫法 mybatis是现在的叫法

    2、iBatis能干什么

    数据库的访问(CRUD)

    整合缓存、还可以给类取别名、IBatis还提供了整合Spring的第三方的包

    3、为什么要学习这个iBatis

    上面的理由已经很充分了

    4、ibatis的简单的使用

    4.1、导包

    <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!--第一步:导包--> <!--下面就是iBatis的相关的包--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!--mysql的驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.5.10</version> </dependency> <!--日志门面--> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency>

    4.2、编写mybatis.xml配置文件

    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!--这个文件的作用:简单的说就是对mybatis的全局配置--> <configuration> <!-- environments:环境 s 可以配置等多个环境 这里配置的环境是:数据库的连接信息 default:如果配置了多个环境 默认使用哪一个环境 --> <environments default="mysql"> <!--配置一个环境:id:表示的是这个环境的名字 逻辑意义上是可以随便写的 --> <environment id="mysql"> <!--配置的是事物的类型 默认配置JDBC就可以了 一般情况下使用的就是这个类型--> <transactionManager type="JDBC"></transactionManager> <!--这个配置的是数据源 这里你可以认为是固定写法--> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///cd200101"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> </dataSource> </environment> <!--这里是可以配置多个环境的 要使用哪一个环境那么就就配置上面的default就可以了 --> <environment id="oracle"> <transactionManager type=""></transactionManager> <dataSource type=""></dataSource> </environment> </environments> <!--在全局配置文件中引入mapper.xml的配置文件--> <mappers> <mapper resource="UserMapper.xml"></mapper> </mappers> </configuration>

    4.3、编写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"> <!--nameSpace:命名空间 这个命名空间和其他的命名空间不能重复 一般情况下 实体Mapper 逻辑上是可以随便写的 但是实际上要见名之意 --> <mapper namespace="UserMapper"> <!--insert:表示的是 添加数据到数据库 id:表示的是方法的名字 备注:标签之间 就是写SQL语句的地方 --> <insert id="add"> insert into t_user(userName,password) values('小小波','123'); </insert> </mapper>

    4.4、编写测试文件

    /** * 测试HelloWolrd程序 */ @Test public void testA() throws IOException { //第一步:找到mybatis.xml这个配置文件 Reader reader = Resources.getResourceAsReader("mybatis.xml"); //第二步:创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //通过工厂 构建 咋们的SqlSession对象 //sqlSession这个对象就是用来操作 数据库的对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //接下来就可以操作数据库了 sqlSession.insert("UserMapper.add"); //接下来提交和关闭 sqlSession.commit(); sqlSession.close(); }

    5、iBatis的基本的增删改查的玩法

    5.1、增删改查的玩法

    public class Test001 { /** * 测试HelloWolrd程序 */ @Test public void testA() throws IOException { //第一步:找到mybatis.xml这个配置文件 Reader reader = Resources.getResourceAsReader("mybatis.xml"); //第二步:创建SqlSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); //通过工厂 构建 咋们的SqlSession对象 //sqlSession这个对象就是用来操作 数据库的对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //接下来就可以操作数据库了 sqlSession.selectOne("UserMapper.delete"); // System.out.println("查询到的数据是:"+user); //接下来提交和关闭 sqlSession.commit(); sqlSession.close(); } /** * 这里是测试类 */ @Test public void testAdd(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); sqlSession.insert("UserMapper.add"); myBatisUtils.close(); } /** * 这里是测试类 */ @Test public void testUpdate(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); sqlSession.insert("UserMapper.update"); myBatisUtils.close(); } @Test public void testQuery(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); Object user = sqlSession.selectOne("UserMapper.queryById"); System.out.println("对象是:"+user); myBatisUtils.close(); } @Test public void testDelete(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); Object user = sqlSession.selectOne("UserMapper.delete"); System.out.println("对象是:"+user); myBatisUtils.close(); } }

    6、iBatis的基本的工具类的使用

    public class MyBatisUtils { //这个类是可以携程成员变量的 private SqlSessionFactory sqlSessionFactory=null; //保存一个线程局部变量 private ThreadLocal<SqlSession> threadLocal; { //需要加载资源 try { threadLocal=new ThreadLocal<>(); Reader reader = Resources.getResourceAsReader("mybatis.xml"); sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader); } catch (IOException e) { e.printStackTrace(); } } /** * 获取操作数据库的对象 * @return */ public SqlSession getSqlSession(){ /** * 编写访问数据库 * 1:在一个方法体里面 你调用任何多次数据库 我们只是要求 打开一次数据库 以及关闭一次就可以了 * 2;简单的说连接是可以重用的 */ SqlSession sqlSession = threadLocal.get(); if(null!=sqlSession){ //说明当前线程不是第一次访问数据库 return sqlSession; } //执行到这里 说明是第一次访问数据库 sqlSession=sqlSessionFactory.openSession(); //放到线程标记中去 threadLocal.set(sqlSession); return sqlSession; } public void close(){ SqlSession sqlSession = threadLocal.get(); if(null!=sqlSession){ sqlSession.commit(); sqlSession.close(); //将线程的局部变量置为空 threadLocal.remove(); } } }

    7、iBatis的数据传参的问题

    7.1、传递简单参数

    <!--传递简单参数 通过id更新数据 parameterType:表示的是传进去的参数的数据类型 这个数据类型有两种写法 1:写Java中数据类型的全路径 java.lang.String java.lang.Integer 2:使用mybatis中的数据类型 这个数据类型与 java中的数据类型是一一对应的 #{写对应的key的名字} 简单的数据类型 一个字符串 一个int 一个float 没有key 那么这个时候 这个key是 可以随便写的 但是为了见名之意 一般写成value --> <update id="update1" parameterType="string"> update t_user set password='5555' where userName=#{value} </update> sqlSession.insert("UserMapper.update1","小波波");

    7.2、传递map集合

    <update id="delete" parameterType="map"> delete from t_user where userName=#{userName} and password=#{password} </update> Map<String,String> map=new HashMap<>(); map.put("userName","小波波"); map.put("password","5555"); sqlSession.insert("UserMapper.delete",map);

    7.3、传递自定义的类的对象

    <!--通过用户名和密码找到用户对象 表示的是传递的是 用户对象 --> <select id="findUserByNameAndPassword"parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User"> select * from t_user t where t.userName=#{userName} and t.password=#{password} </select> User user = new User(1, "小小波", "123"); User user1= sqlSession.selectOne("UserMapper.findUserByNameAndPassword",user);

    疑问:能不能一次性传递多个简单的参数呢?

    因为后面在接受数据的时候 采用的key是随机的 也就说 可以随便写的 假设你传递了多个简单的参数 那么后面如何区分 这个值是哪一个的 呢?

    没有办法进行传递 ------ 如果要进行传递 那么你就封装成 map集合 或者 java的类

    8、动态SQL的问题

    什么是动态SQL? 在进行查询的时候 会根据前端传递数据的条件 来动态的进行SQL语句的拼接的这种方法 就称为动态SQL

    需求:前端随地的给定一串id 要求的是 这一串的id的用户信息全部查询出来 这一串id可以是任意的

    id:6,7,9 或者 6,7,8,9 或者 7,8,9

    select * from t_user where id in(不确定)

    动态sql解决的问题

    8.1、传递数组来解决问题

    <!--动态sql传递数组的问题 通过一连串的id 找用户对象 select * from t_user where id in (6,7,8) <if>标签用来做条件判断 如果前端传递的是数组类型的数据 那么 这里使用 list来接受 遍历数据的时候 那么还是使用 array来做遍历 collection:表示的是要遍历的这个集合或者数组 open:sql语句的构成 以什么开始 close:SQL语句的构成以什么结束 separator:遍历出来的数据之间使用什么进行分割 item:每一次遍历出来的数据是什么 注意:每一次遍历出来的数据 要使用 #{遍历的名字} 去进行获取 --> <select id="findUserByIds" parameterType="list" resultType="com.qf.cd.helloworld.User"> select * from t_user <if test="array != null"> where id <foreach collection="array" open="in (" close=")" separator="," item="id"> #{id} </foreach> </if> </select>

    8.2、传递个集合来解决问题

    <!--下面传递集合来解决问题--> <select id="findUserByIds2" parameterType="list" resultType="com.qf.cd.helloworld.User"> select * from t_user <if test="list != null"> where id <foreach collection="list" open="in (" close=")" separator="," item="id"> #{id} </foreach> </if> </select>

    8.3、更新数据(插入数据)

    <!--插入数据 prefix:前缀 拼接的前缀 suffix:拼接的后缀 suffixOverrides:这个是去掉结束位置的某一个符号 可以是任意的 prefixOverrides:去掉开始的符号 这个符号是任意的 --> <insert id="insert222" parameterType="com.qf.cd.helloworld.User"> insert into t_user <trim prefix="(" suffix=")" suffixOverrides="," prefixOverrides=""> <if test="userName != null"> userName, </if> <if test="password !=null"> password </if> </trim> <trim prefix="values(" suffix=")" suffixOverrides=","> <if test="userName != null"> #{userName}, </if> <if test="password !=null"> #{password} </if> </trim> </insert>

    8.4、动态sql和sql片段

    <select id="findUserByCondition" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User"> select * from t_user where 1=1 <if test="userName != null"> and userName=#{userName} </if> <if test="password !=null"> and password=#{password} </if> </select> <select id="findUserByCondition1" parameterType="com.qf.cd.helloworld.User" resultType="com.qf.cd.helloworld.User"> select * from t_user <include refid="xiaobobo"></include> </select> <!--抽取sql标签 抽取的sql在任何地方都可以进行调用 --> <sql id="xiaobobo"> <where> <if test="userName != null"> and userName=#{userName} </if> <if test="password !=null"> and password=#{password} </if> </where> </sql>

    9、iBatis的结果集的返回问题

    9.1、返回简单参数

    <!--返回简单参数 需求:通过用户名 查询用户id --> <select id="findIdByUserName" parameterType="string" resultType="int"> select id from t_user where userName=#{value} </select> Object id=sqlSession.selectOne("UserMapper.findIdByUserName","小小波");

    9.2、返回自定义的类的对象

    <!--返回简单参数 需求:通过id 查询用户对象 --> <select id="findUserById" parameterType="int" resultType="com.qf.cd.helloworld.User"> select * from t_user where id=#{value} </select> Object user=sqlSession.selectOne("UserMapper.findUserById",9);

    9.3、返回list集合 但是集合中是常见的数据类型

    需求:通过一连串的id查询用户的名字

    <!--返回简单参数 需求:通过一连串的id 查询一连串的名字 如果返回集合的数据类型 那么下面的结果集的返回只用写 集合中泛型的数据类型就OK了 --> <select id="findNamesByIds" resultType="string"> select userName from t_user where id in(6,7,9) </select> List<String> strs=sqlSession.selectList("UserMapper.findNamesByIds");

    9.4、返回一个集合 集合中的泛型是自定义的类的类型

    <!-- 需求:查询所有的用户 结果集只是写 泛型中的数据类型就OK了 --> <select id="findUserAll" resultType="com.qf.cd.helloworld.User"> select * from t_user </select> List<User> users=sqlSession.selectList("UserMapper.findUserAll");

    9.5、数据库的字段和实体不对应怎么办?

    9.5.1、取别名解决这个问题
    <!--字段不对应的问题怎么解决 取别名的解决方案--> <select id="findDeptAll" resultType="com.qf.cd.result.Dept"> select id as deptId,dept_name as deptName,dept_des as deptDes from t_dept </select>
    9.5.2、通过结果集映射解决这个问题
    <!--配置结果集的映射关系--> <resultMap id="findDeptAll2ResultMap" type="com.qf.cd.result.Dept"> <!--配置主键映射--> <id property="deptId" column="id"></id> <!--配置普通字段的映射--> <result property="deptName" column="dept_name"></result> <result property="deptDes" column="dept_des"></result> </resultMap> <!--字段不对应的问题怎么解决 设置结果集的映射关系--> <select id="findDeptAll2" resultMap="findDeptAll2ResultMap"> select * from t_dept </select>

    10、注意事项

    10.1、增删改的标签或者方法也好、是可以随便换的、因为最终真正的执行的是sql语句、跟调用的方法是没有关系的

    10.2、查询的方法一般不能换、因为查询要返回具体查询出来的值、不是返回影响的行数

    11、一对一映射的关系

    需求:一个用户拥有一个身份证、一个身份证唯一的对应了一个用户

    用户------------------身份证----------------->一对一的关系 在查询 用户的时候 我希望的是 能查询出身份证

    11.1、先准备用户实体

    @Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String userName; private String password; private Idcard idcard; }

    11.2、准备IdCard实体

    @Data @AllArgsConstructor @NoArgsConstructor public class Idcard { private int id; private Date birthday; private String cardNum; private int userId; }

    11.3、编写方法的配置

    <resultMap id="findUserAllResultMap" type="com.qf.cd.one2one.User"> <!--配置结果集的映射--> <id property="id" column="id"></id> <!--配置普通字段的映射--> <result property="userName" column="userName"></result> <result property="password" column="password"></result> <!--接下来配置一对一的映射关系 property:这个实际上就是 java实体中 对象关系的名字 javaType:数据类型(全限定名) --> <association property="idcard" javaType="com.qf.cd.one2one.Idcard"> <!--配置主键映射--> <id property="id" column="idcardId"></id> <result property="birthday" column="birthday"></result> <result property="cardNum" column="cardNum"></result> <result property="userId" column="userId"></result> </association> </resultMap> <select id="findUserAll" resultMap="findUserAllResultMap"> select * from t_user t1,t_idcard t2 where t1.id=t2.userId </select>

    11.4、测试

    @Test public void testAdd(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); List<User> users=sqlSession.selectList("UserMapper.findUserAll"); System.out.println(users); myBatisUtils.close(); }

    12、一对多的映射关系

    12.1、准备Dept对象

    @Data @AllArgsConstructor @NoArgsConstructor public class Dept { private int deptId; private String deptName; private String deptDes; private List<Employee> emps; }

    12.2、准备Employee对象

    @Data @AllArgsConstructor @NoArgsConstructor public class Employee { private int empId; private String empName; private int gender; }

    12.3、准备配置文件

    <!--一对多的结果集映射--> <resultMap id="findDept1AllResultMap" type="com.qf.cd.one2many.Dept"> <!--主键映射--> <id property="deptId" column="deptId"></id> <!--普通字段映射--> <result property="deptName" column="deptName"></result> <result property="deptDes" column="deptDes"></result> <!--一对多的映射--> <collection property="emps" ofType="com.qf.cd.one2many.Employee"> <!--主键字段--> <id property="empId" column="empId"></id> <!--普通字段--> <result property="empName" column="empName"></result> <result property="gender" column="gender"></result> </collection> </resultMap> <!--玩一个一对多的映射关系--> <select id="findDept1All" resultMap="findDept1AllResultMap"> select * from t_dept1 t1,t_emp t2 where t1.deptId=t2.deptId </select>

    12.4、测试

    @Test public void testDelete(){ MyBatisUtils myBatisUtils = new MyBatisUtils(); SqlSession sqlSession = myBatisUtils.getSqlSession(); List<Dept> depts=sqlSession.selectList("UserMapper.findDept1All"); System.out.println(depts); myBatisUtils.close(); }

    13、取别名的问题

    为什么要整个别名? 因为我们很多时候在写 这个java类型的时候 都写的的全路径

    简单的说就是为了解决 传入参数的类型过长 以及 返回参数的类型 过长的问题

    mybatis.xml中进行配置

    <!--取别名--> <typeAliases> <!-- type:是要取别名的这个java类型 alias:这个是别名的名字 别名一般情况下是取给java实体类的 po dto --> <!-- <typeAlias type="com.qf.cd.one2many.Dept" alias="deptbobo"></typeAlias> <typeAlias type="com.qf.cd.one2many.Employee" alias="empbobo"></typeAlias>--> <!--这个就表示的是给这个包里所有的类都取别名 默认的别名的名字是 类名的首写字母小写 --> <package name="com.qf.cd.one2many"></package> </typeAliases>

    14、懒加载的问题

    14.1、关闭积极的加载、开启懒加载

    <!--iBatis本身的设置 --> <settings> <!--是否使能延迟的加载 --> <setting name="lazyLoadingEnabled" value="true" /> <!--关闭那个积极的加载 --> <setting name="aggressiveLazyLoading" value="false" /> </settings>

    14.2、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"> <!--nameSpace:命名空间 这个命名空间和其他的命名空间不能重复 一般情况下 实体Mapper 逻辑上是可以随便写的 但是实际上要见名之意 --> <mapper namespace="UserMapper"> <resultMap id="findUserAllResultMap" type="com.qf.cd.one2one.User"> <!--配置结果集的映射--> <id property="id" column="id"></id> <!--配置普通字段的映射--> <result property="userName" column="userName"></result> <result property="password" column="password"></result> <!--接下来配置一对一的映射关系 property:这个实际上就是 java实体中 对象关系的名字 javaType:数据类型(全限定名) column:这个是为了将上面的某一个列的内容给映射下来 相当于 调用方法的时候要传值 select:相当于要调用另外的mapper来实现整个逻辑 --> <association property="idcard" column="id" javaType="com.qf.cd.one2one.Idcard" select="IdCardMapper.findIdCardByUserId" fetchType="lazy"> </association> </resultMap> <!--玩的是一对一的映射关系--> <select id="findUserAll" resultMap="findUserAllResultMap"> select * from t_user where id=6 </select> </mapper>

    14.3、测试问题

    @Test public void testAdd() throws IOException { Reader reader = Resources.getResourceAsReader("mybatis.xml"); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); SqlSession sqlSession = sqlSessionFactory.openSession(); User users=sqlSession.selectOne("UserMapper.findUserAll"); System.out.println("中国好"); System.out.println("中国好"); System.out.println("中国好"); System.out.println("中国好"); //执行这一句话的时候才会 执行 IdCard中的sql语句 // Date birthday = users.getIdcard().getBirthday(); // System.out.println(birthday); sqlSession.commit(); sqlSession.close(); }
    Processed: 0.017, SQL: 9