Mybatis

Mybatis

  • l MyBatis是一款优秀的持久层框架

  • l 它支持定制化SQL、 存储过程以及高级映射。

  • l MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。

  • l MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和Java的pojo

  • l Objects, 普通老式Java对象为数据库中的记录。

  • l MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了

  • l google code, 并且改名为MyBatis。

  • l 2013年11月迁移到Github。

持久化

数据持久化

1) 持久化就是将程序的数据在持久状态和瞬时状态转化的过程

2) 内存:断电即失

3) 数据库(Jdbc), io文件持久化。

持久层

Dao层,Service层, Controller层....

1) 完成持久化工作的代码块

2) 层界限十分明显。

优点

  • l 简单易学

  • l 灵活

  • l sq|和代码的分离,提高了可维护性。

  • l 提供映射标签,支持对象与数据库的orm字段关系映射

  • l 提供对象关系映射标签,支持对象关系组建维护

  • l 提供xml标签,支持编写动态sq|

生命周期和作用域

生命周期,和作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqISessionFactoryBuilder

  • 一旦创建了SqlSessionFactory, 就不再需要它了

  • 局部变量

SqlSessionFactory

  • 说白了就是可以想象为:数据库连接池

  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一-直存在, 没有任何理由丢弃它或重新创建 另一个实例。

  • 因此SqlSessionFactory的最佳作用域是应用作用域

  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 连接到连接池的一个请求

  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用 域。

  • 用完之后需要赶紧关闭,否则资源被占用

配置环境

1.新建maven项目 (父项目)

idea直接创建maven项目

删除src目录(为了创建父工程)

在pom.xml中 导入依赖 mybatis依赖 mysql依赖 junit依赖(都是在中央仓库复制粘贴的)

     <!--    依赖 -->
     <dependencies>
 ​
         <!--mybatis-->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.2</version>
         </dependency>
 ​
         <!--mysql-->
         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.47</version>
         </dependency>
 ​
         <!--junit-->
         <!-- https://mvnrepository.com/artifact/junit/junit -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
 ​
 ​
     </dependencies>

2.配置数据库文件

配置Mybaits-config文件(相当于之前的jdbc.proper什么什么的文件)

在resources目录下

下面为官网代码(去官网上去找代码)

 `<?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>`
 ​
  `<environments default="development">`
 ​
   `<environment id="development">`
 ​
    `<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="org/mybatis/example/BlogMapper.xml"/>`
 ​
  `</mappers>`
 ​
 `</configuration>`

Huiex的代码

     <!--    依赖 -->
     <dependencies>
 ​
         <!--mybatis-->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.2</version>
         </dependency>
 ​
         <!--mysql-->
         <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.47</version>
         </dependency>
 ​
         <!--junit-->
         <!-- https://mvnrepository.com/artifact/junit/junit -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.12</version>
             <scope>test</scope>
         </dependency>
 ​
 ​
     </dependencies>

3.创建一个模块(创建子项目)

4.连接数据库

5.编写MybatisUtils工具类

获取sqlSession对象

相当于注册驱动 获取连接

 package com.Huiex.utils;
 ​
 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.InputStream;
 ​
 /**工具类*/
 //目的 SqlSessionFactory  -->  Session
 public class MybatisUtils {
 ​
 //  获取配置文件
   //提升作用域
   private static SqlSessionFactory sqlSessionFactory;
   //设置为静态(好,懂得都懂)
 ​
   static {
      //使用Mybatis,第一步:获取sqLSessionFactory对象(代码书写按照官网文档)
     try {
 ​
       String resource = "mybatis-config.xml";
       InputStream inputStream = Resources.getResourceAsStream(resource);//加载流
       sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);//获取流
 ​
     } catch (Exception e) {
       e.printStackTrace();
     }
   } 
     
   //既然有了SqlSessionFactory, 顾名思义,我们就可以从中获得SqlSession 的实例了。
   //SqlSession完全包含了面向数据库执行SQL命令所需的所有方法。
   public static SqlSession getSqlSession(){
       SqlSession sqlSession = sqlSessionFactory.openSession();
       return sqlSession;
   }
 ​
 }

6.创建Bean

在pojo包先创建

 package com.Huiex.pojo;
 ​
 public class User {
     private int id;
     private String name;
     private String pwd;
 ​
     public User() {
     }
     
     //然后就是bean的常规了 get set什么什么的

7.创建接口类

 package com.Huiex.dao;
 ​
 import com.Huiex.pojo.User;
 ​
 import java.util.List;
 import java.util.Map;
 ​
 public interface UserMapper {
     //查询所有
     List<User> getUserList();
 ​
     //根据id查询用户信息
     User getUserById(int id);
 ​
     //插入一个用户
     Integer addUser(User user);
 ​
     //修改用户
     Integer updateUser(User user);
 ​
     //删除用户
     Integer deleteUser(int id);
 ​
     //Map
     int addUserMap(Map<String,Object> map);
 ​
     //like
     List<User> getUserLike(String value);
 ​
 }

8.创建UesrMapper.xml

UesrMapper.xml相当于创建之前的实现类Imlp

按理说,应该创建Imlp实现类,但是Mybatis特点就是用xml代替

接口实现类由原来的UserDaolmpl转变为一个Mapper配置文件.

 <?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(DAO)接口路径"  绑定一个对应的Mapper(DAO)接口-->
 <mapper namespace="com.Huiex.dao.UserMapper">

9. 注册Mapper.xml文件

每一个Mapper.xml文件 都需要在Mybatis核心配置文件中注册

在mybatis-config.xml文件中加上

 <!--    每一个Mapper.xml文件 都需要在Mybatis核心配置文件中注册-->
     <mappers>
         <mapper resource="com/huiex/dao/UserMapper.xml"/>
     </mappers>

UsesrMapper.xml就是Mapper.xml类型的文件

10. 资源导出问题

1) 因为配置文件应该放在resources但是UserMapper.xml文件在java包下的dao目录下所以需要maven的资源过滤器

2) maven由于他的约定大于配置,我们之后可以能遇到我们写的配置文件,无法被导出或者生效的问题,解决方法:资源过滤器

3) 成功导出或者生效后会在target中显示出来

在pom.xml文件中加入一下代码

 
<!--在build中配置resources,来防止我们资源导出失败的问题-->
     <build>
         <resources>
             <resource>
                 <directory>src/main/resources</directory>
                 <includes>
                     <include>**/*.properties</include>
                     <include>**/*.xml</include>
                 </includes>
                 <filtering>true</filtering>
             </resource>
             <resource>
                 <directory>src/main/java</directory>
                 <includes>
                     <include>**/*.properties</include>
                     <include>**/*.xml</include>
                 </includes>
                 <filtering>false</filtering>
             </resource>
         </resources>
     </build>
 ​

11.建一个测试类

在test包下的java目录下创建

测试包中的目录要和java包中的目录保持一致

常见问题

1) 没有驱动下载驱动

2) 时区不对就在jdbc:mysql://localhost:3306/mybatis(数据库的名字)

后面加?serverTimezonehai

jdbc:mysql://localhost:3306/mybatis?serverTimezone=Asia/Shanghai

增删改查CRUD

使用

1.获得sqlSession连接 SqlSession sqlSession = MybatisUtils.getSqlSession();

2.获取getMapper对象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

3.调用JDBC方法

4.提交事务 sqlSession.commit();

5.关闭资源 sqlSession.close()

1. 写接口

在userMapper接口类中写

 package com.Huiex.dao;
 ​
 import com.Huiex.pojo.User;
 import java.util.List;
 import java.util.Map;
 ​
 public interface UserMapper {
     //查询所有
     List<User> getUserList();
 ​
     //根据id查询用户信息
     User getUserById(int id);
 }

2. 编写对应的sql语句

在UesrMapper.xml中写sql语句

 
<?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(DAO)接口路径"  绑定一个对应的Mapper(DAO)接口-->
 <mapper namespace="com.Huiex.dao.UserMapper">
 ​
     <select id="getUserList" resultType="com.Huiex.pojo.User">
         select * from mybatis.user  /*SQL语句*/
     </select>
     <!--<select查询标签   id 名字(相当于实现接口方法的名字)
                          parameterType 参数类型   resultType 返回结果类型(查询才有)   #{}相                         当于占位符-->
     <select id="getUserById" parameterType="int" resultType="com.Huiex.pojo.User">
         select * from mybatis.user where id=#{id};
     </select>

测试

     
@Test
     public void getUserById(){
 ​
         /**官方建议 本段代码try catch 但也可以没有*/
 ​
         //1.获得sqlSession连接  (通过Mybatis工具类获得sqlSession对象)
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         //2.获取getMapper对象   (通过sqlSession中的 getMapper方法获得UserMapper接口)
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
         //3.调用JDBC方法        (通过UserMapper对象调用  对应需要使用的JDBC方法(增删改查))
         User userById = userMapper.getUserById(3);
 ​
         System.out.println(userById);
         sqlSession.close();
     }

增删改

1. 写接口

在userMapper接口类中写

 
package com.Huiex.dao;
 ​
 import com.Huiex.pojo.User;
 import java.util.List;
 import java.util.Map;
 ​
 public interface UserMapper {
     //查询所有
     List<User> getUserList();
 ​
     //根据id查询用户信息
     User getUserById(int id);
 ​
     //插入一个用户
     Integer addUser(User user);
 ​
     //修改用户
     Integer updateUser(User user);
 ​
     //删除用户
     Integer deleteUser(int id);
 ​
     //Map
     int addUserMap(Map<String,Object> map);
 ​
     //like
     List<User> getUserLike(String value);
 }

2. 编写mapper中的sql语句

<?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(DAO)接口路径"  绑定一个对应的Mapper(DAO)接口-->
 <mapper namespace="com.Huiex.dao.UserMapper">
     <!--insert插入标签  #{id},#{name},#{pwd} 对象中的属性可以直接取出来  #{}相当于占位符-->
     <insert id="addUser" parameterType="com.Huiex.pojo.User">
         insert into mybatis.user (id,name,pwd) values (#{id},#{name},#{pwd});
     </insert>
     <!--update修改标签-->
     <update id="updateUser" parameterType="com.Huiex.pojo.User">
         update mybatis.user set name=#{name} ,pwd=#{pwd} where id=#{id};
     </update>
     <!--delete删除标签-->
     <delete id="deleteUser" parameterType="int">
         delete from mybatis.user where id=#{id};
     </delete>

事务机制

在Mybatis中默认为关闭事务,

需要在sql语句执行完后,手动提交

如果不自动提交,那么虽然执行成功,但是表数据不会更改

作用:

在测试时,既可以测试代码是否成功又可以有效防止源数据被污染

改变事务的开关

3.测试

  • 增删改一定要写提交事务

  • 增删改返回值为int

     
@Test
     public void addUserMap(){
         //1.获得sqlSession连接  (通过Mybatis工具类获得sqlSession对象)
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         //2.获取getMapper对象   (通过sqlSession中的 getMapper方法获得UserMapper接口)
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
         //3.调用JDBC方法        (通过UserMapper对象调用  对应需要使用的JDBC方法(增删改查))
         HashMap<String, Object> map = new HashMap<String, Object>();
 ​
         map.put("userid",11);
         map.put("password","66666666");
         int i = userMapper.addUserMap(map);
         System.out.println(i);
 ​
         sqlSession.commit();//提交事务
         sqlSession.close();//关闭连接
     }

     
@Test
     public void deleteUser(){
         //1.获得sqlSession连接  (通过Mybatis工具类获得sqlSession对象)
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         //2.获取getMapper对象   (通过sqlSession中的 getMapper方法获得UserMapper接口)
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
         //3.调用JDBC方法        (通过UserMapper对象调用  对应需要使用的JDBC方法(增删改查))
         Integer integer = userMapper.deleteUser(10);
         
         System.out.println(integer);
 ​
         sqlSession.commit();//提交事务
         sqlSession.close();//关闭连接
     }

    @Test
     public void updateUser(){
         //1.获得sqlSession连接  (通过Mybatis工具类获得sqlSession对象)
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         //2.获取getMapper对象   (通过sqlSession中的 getMapper方法获得UserMapper接口)
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
         //3.调用JDBC方法        (通过UserMapper对象调用  对应需要使用的JDBC方法(增删改查))
         Integer integer = userMapper.updateUser(new User(9, "zyx", "777"));
 ​
         System.out.println(integer);
 ​
         sqlSession.commit();//提交事务
         sqlSession.close();//关闭连接
     }

Map

  • 当我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map

例如一个表中只需要修改其中一个字段时,就只需要用map作为参数,在写sql语句时候只需要值map设置(put)需要修改的属性,不用再直接传入实体类然后每个属性都要改

1.写接口

 public interface UserMapper {
     //Map
     int addUserMap(Map<String,Object> map);
 }

2.编写mapper中的sql语句

     <update id="addUserMap" parameterType="map">
         update mybatis.user set pwd = #{password} where id = #{userid};
     </update>

3.测试

     
@Test
     public void addUserMap(){
         //1.获得sqlSession连接  (通过Mybatis工具类获得sqlSession对象)
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         //2.获取getMapper对象   (通过sqlSession中的 getMapper方法获得UserMapper接口)
         UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
         //3.调用JDBC方法        (通过UserMapper对象调用  对应需要使用的JDBC方法(增删改查))
         
         HashMap<String, Object> map = new HashMap<String, Object>();
         map.put("userid",11);
         map.put("password","66666666");
         
         int i = userMapper.addUserMap(map);
         System.out.println(i);
 ​
         sqlSession.commit();//提交事务
         sqlSession.close();//关闭连接
     }
 ​

like

各个sql语句标签返回值

  • insert,返回值是:新插入行的主键(primary key);需要包含<selectKey>语句,才会返回主键,否则返回值为null。

  • update/delete,返回值是:更新或删除的行数;无需指明resultClass;但如果有约束异常而删除失败,只能去捕捉异常。

  • queryForObject,返回的是:一个实例对象或null;需要包含<select>语句,并且指明resultMap;

  • queryForList,返回的是:实例对象的列表;需要包含<select>语句,并且指明resultMap;

配置文件(mybatis-confing.xml)

  • mybatis使用要先配置文件,在resources(资源)包下建立 mybatis-confing.xml 文件

  • MyBatis 的配置文件包含了会深深影响MyBatis行为的设置和属性信息。

配置文件中的标签顺序要按照以下顺序

 configuration (配置)
 properties (属性)
 settings (设置)
 typeAliases (类型别名)
 typeHandlers (类型处理器)
 objectFactory (对象工厂)
 p1ugins (插件)
 environments (环境配置)
     environment (环境变量)
     transactionManager (事务管理器)
     datasource (数据源)
 databaseIdProvider (数据库厂商标识)
 mappers (映射器)

属性 (properties)

在resources(资源)包下建立 db.properties 文件

 driver=com.mysql.jdbc.Driver
 url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&\
     serverTimezone=Asia/Shanghai&useUnicode=true&\
     characterEncoding=utf-8
     #url中 应该是数据库地址,useSSl安全连接(建议问号后面加useSSL,不要在&后面加,这个玩意很重要)
     #useUnicode utf&characterEncoding懂得懂得
     #serverTimezone 时区
 username=root
 password=183303

在mybatis-confing.xml 文件中 引入外部配置文件

 <?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核心配置文件-->
 <configuration>
 -------------------------------------------------------------------------------------
     <!--引入外部配置文件-->
     <properties resource="db.properties"/>

作用:可以简化代码,懂得都懂和JDBC一样,对比看下面环境配置里面的代码

环境配置(environments)

  1. MyBatis可以配置成适应多种环境

  2. Mybatis默认的事务管理器就是JDBC,连接池: POOLED

头文件

 
<?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

 <configuration>

环境配置

  • 通过改变default的值 切换环境

     
<!--environments环境   default="development"定义为开发环境-->
     <environments default="text">-------------------------------------------- 开发环境

事务管理器

  • 在MyBatis中有两种类型的事务管理器(也就是type="[ JDBC|MANAGED ]"

 <environment id="development">---------------------------------------id 环境名称 
             <transactionManager type="JDBC"/>---------------------------------事务管理器

数据源

  • Mybatis默认连接池: POOLED

<dataSource type="POOLED">-------------------------------------------数据源
                 <property name="driver" value="com.mysql.jdbc.Driver"/>
                 <property name="url" value="jdbc:mysql://localhost:3306/mybatis?                                                useSSL=false&amp;
                                             serverTimezone=Asia/Shanghai&amp;                                               useUnicode=true&amp;characterEncoding=utf-8"/>
                 <property name="username" value="root"/>
                 <property name="password" value="183303"/>
                 <property name="defaultAutoCommit" value="false"/>
             </dataSource>

配置多套运行环境

  • 可以配置多个环境,但每个SqlSessionFactory实例只能选择一种环境

<environment id="test"> ----------------------------------------id 环境名称
             <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}"/>
                 <property name="defaultAutoCommit" value="false"/>------关闭自动提交事务
             </dataSource>
         </environment>
     </environments>
 </configuration>

在核心配置文件中映入

可以直接引入外部文件 可以在其中增加一些属性配置 如果两个文件有同一个字段,优先使用外部配置文件的!

类型别名(typeAliases)

作用

  • 类型别名是为Java类型设置一个短的名字。

  • 它只和XML配置有关,存在的意义仅在于用来减少类完全限定名的冗余

即 将 mapper类中的 XML 的com.Huiex.pojo.User的 实体类 设置一个别名

<select id="getUserList" resultType="com.Huiex.pojo.User">
         select * from mybatis.user  /*SQL语句*/
     </select>

使用

<typeAliases>标签给实体类起别名

两种使用方法:

  • <typeAlias>标签

    <typeAlias type="com.Huiex.pojo.User" alias="User"/>

  • <package>标签

    <package name="com.Huiex.pojo"/>

    1)指定一个包名, MyBatis 会在包名下面搜索需要的Java Bean,扫描实体类的包

    2)它的默认别名就为这个类的类名,首字母小写

    3)如需要改,可以在实体上增加注解@Alias

     package com.Huiex.pojo;
     ​
     import org.apache.ibatis.type.Alias;
     ​
     @Alias("user")//--------------------------------------------------------------注解
     public class User {
         private int id;
         private String name;
         private String pwd;
     ​
         public User() {
         }

    mybatis-confing.xml配置文件中

 
<?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核心配置文件-->
 <configuration>
 ​
     <!--引入外部配置文件-->
     <properties resource="db.properties"/>
 -------------------------------------------------------------------------------------
     <!--可以给实体类起别名-->
     <typeAliases>
         <typeAlias type="com.Huiex.pojo.User" alias="user"/>
         <package name="com.Huiex.pojo"/>
     </typeAliases>
 -------------------------------------------------------------------------------------
 ​
     <!--environments环境   default="development"定义为开发环境-->
     <environments default="development">

改变后的mapper类中的 XML

<select id="getUserList" resultType="user">
         select * from mybatis.user  /*SQL语句*/
     </select>

区别

  1. 在实体类比较少的时候,使用第一种方式,如果实体类十分多,建议使用第二种

  2. 第一种可以DIY别名,第二种则.不行(如果非要改,需要在实体上增加注解)

  3. typealais>注解>限定包名

设置(setting)

映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

方式一:

使用相对于类路径的资源引用

     
<mappers>
         <mapper resource="com/huiex/dao/UserMapper.xml"/>
</mappers>

方式二:

使用class文件绑定注册

     <mappers>
         <mapper class="com.Huiex.dao.UserMapper"/>
     </mappers>

  • 接口和他的Mapper配置文件必须同名!

  • 接口和他的Mapper配置文件必须在同一个包下!

方式三:

使用扫描包进行注入绑定

     <mappers>
         <package name="com.Huiex.dao"/>
     </mappers>

  • 接口和他的Mapper配置文件必须同名!

  • 接口和他的Mapper配置文件必须在同一个包下!

结果集映射(resultMap)

解决属性名和字段名不一致的问题 (例如数据库中习惯用Xxx_Yyy,而java中用XxxYxx)

单表查询(普通映射)

问题引入

数据库中表的属性和JavaBean中的属性 名称不一样

一般查询会用到,因为查询需要将查询到的表内容传给JavaBean

 数据库中  id name pwd
 bean中   id name password

理解

<select>标签中的返回值设为从<resuitMap>标签中获取(结果集),

然后在<resuitMap>标签中进行返回值的映射

使用

<select>标签中用<resultMap>代替<resultType>属性(返回值类型)

然后在<resuitMap>标签中设置id(就只是一个名称、标识) type(才是返回值类型)

<resuit>标签进行想需要的返回值的映射(就是起一个别名)

     <resultMap id="UserMap" type="User">
         <result column="pwd" property="password"/>
     </resultMap>
 ​
     <select id="getUserList" resultMap="UserMap">
         select * from mybatis.user  /*SQL语句*/
     </select>
  • resultmap元素是MyBatis中最重要最强大的元素

  • ResultMap的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。

多表查询(嵌套映射)

问题引入

两表通过Teacher的id连接,需要查询student表对应的老师

代码

pojo

 
@Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class Student {
     private int id;
     private String name;
     private Teacher teacher;
             ----------两个表有关联,所以teacher属性类型从Teacher类中得到,所以类型为Teacher对象
 }
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class Teacher {
     private int id;
     private String name;
 }

接口

 
public interface StudentMapper {
     List<Student> getStudent();
 }

mapper

 <?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 ​
 <mapper namespace="com.Huiex.dao.StudentMapper">
 ​
     <select id="getStudent" 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">
         <result property="id" column="sid"/>
         <result property="name" column="sname"/>
         <association property="teacher" column="tname">
             <result property="name" column="tname"/>
         </association>
     </resultMap>
 ​
 </mapper>

理解

先正常用两(多)表查询(连接查询),得出想要的查询结果

但是查询结果中tname(student对应的teacher的name)类型不是Teacher对象类型

     <select id="getStudent" 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">--------------type 设置最后返回值为student
     <result property="id" column="sid"/>----- 把查询到的sid映射到返回值student对象的id属性中
     <result property="name" column="sname"/>---------------------------------------同理
    
 复杂的属性,我们需要单独处理对象: association 集合: collection
     <association property="teacher" javaTyupe="Teacher">----------------看下边
         <result property="name" column="tname"/>
     </association>
 </resultMap>

看这里

 
<association property="teacher" javaType="Teacher">
     --可以看做resulMap的嵌套,property="teacher"还是对应的属性,javaType 设置最后返回值Teacher
     --这样就解决了查询结果中tname(student对应的teacher的name)类型不是Teacher对象类型的问题
     <result property="name" column="tname"/>
     --把查询到的tname映射到返回值Teacher对象的name属性中
 </association>
 --于是最后返回给Student实体类的teacher属性为携带则查询结果的name属性的Teacger对象

现在我是懂了,你不知道,你随意,要是看不懂就算了

使用注解

  • 本质:反射机制实现

  • 底层:动态代理

  • 可以和xml方式一起使用

注解在接口上实现

 import com.Huiex.pojo.User;
 import org.apache.ibatis.annotations.Select;
 import java.util.List;
 ​
 public interface UserMapper {
     @Select("select * from user")
     List<User> getUserList();
 }

在配置文件上映射

和xml一样,要用映射器连接上接口

去看文档上面的映射器

     <mappers>
         <mapper class="com.Huiex.dao.UserMapper"/>
     </mappers>

有参数

@Param()注解

  • 基本类型的参数或者String类型,需要加上

  • 如果只有一个基本类型的话,可以忽略,但是建议加上

  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名

 public interface UserMapper {
     //方法存在多个参数,所有的参数前面必须加上@Param("id")注解
     @Select("select * from user where id=#{id}")
     User getUserById(@Param("id") int id);
 }

  • 引用类型不需要加

 public interface BlogMapper {
     @Insert("insert into blog(id, title, author, create_time, views) values (#{id},#{title},#{author},#{create_time},#{views}")
     int addBlog(Blog blog);
 }

动态SQL

  • 所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面, 去执行一个逻辑代码

  • 动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

  • 建议:

    先在MysqI中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可!

if

使用

<if>标签中的text属性为条件,当成立时,将<if>中的语句拼接到原本的sql语句中

 <mapper namespace="com.Huiex.dao.BlogMapper">
 ​
     <select id="queryBlogIF" parameterType="map" resultType="com.Huiex.pojo.Blog">
         
         select * from mybatis.blog where 1=1-/*不要写分号,因为要拼接,不然回报sql语法错误*/
         <if test="views != null">---------------------------------/*test=里面写表达式*/
             and views = #{views}
         </if>
         <if test="title != null">
             and title = #{title}
         </if>
         
     </select>
 ​
 </mapper>

测试结果

1)有参数时候,满足<if>标签

     @Test
     public void queryBlogIF(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
         HashMap<String, Object> map = new HashMap<>();
         
         map.put("views",1999);------------------------------有参数,执行按照views字段查询
         
         List<Blog> blogList = mapper.queryBlogIF(map);
         for (Blog blogs :
                 blogList) {
             System.out.println(blogs);
         }
         sqlSession.close();
     }

2)同时满足多个if

执行select * from mybatis.blog where 1=1 and views = #{views} and title = #{title}

 @Test
 public void queryBlogIF(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap<String, Object> map = new HashMap<>();
 ​
     map.put("views",1999);
     map.put("author","author");-------------------------结果为同时满足两个条件的查询结果
 ​
     List<Blog> blogList = mapper.queryBlogWhere(map);
     for (Blog blogs :
             blogList) {
         System.out.println(blogs);
     }
     sqlSession.close();
 }

3)都不满足时

     @Test
     public void queryBlogIF(){
         SqlSession sqlSession = MybatisUtils.getSqlSession();
         BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
         HashMap<String, Object> map = new HashMap<>();
                                     ---------------无参数,直接执行查询所有,因为where 1=1
         List<Blog> blogList = mapper.queryBlogIF(map);
         for (Blog blogs :
                 blogList) {
             System.out.println(blogs);
         }
         sqlSession.close();
     }
 ​

where

where元素只会在至少有一个子元素的条件返回SQL子句的情况下才去插入“WHERE"子句。

而且,若语句的开头为“AND”或“OR”,where 元素也会将它们去除。

 <select id="queryBlogChoose" parameterType="map" resultType="com.Huiex.pojo.Blog">
     select * from mybatis.blog
     <where>--------------------------------------------------------where包含的就是子元素
         <if test="views != null">/*test=里面写表达式*/
             and views = #{views}
         </if>
         <if test="title != null">
             and title = #{title}
         </if>
     </where>
 </select>

如果views != null执行成功,则sql语句为select * from mybatis.blog where views = #{views}

如果子元素没有成立的,则sql语句为select * from mybatis.blog

 @Test
 public void queryBlogChoose(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap<String, Object> map = new HashMap<>();
 ​
     map.put("views",9999);-----------------------------结果和上面的if一样
 ​
     List<Blog> blogList = mapper.queryBlogIF(map);
     for (Blog blogs :
             blogList) {
         System.out.println(blogs);
     }
     sqlSession.close();
 }

choose, when, otherwise

有时我们不想应用到所有的条件语句,而只想从中择其-项。针对这种情况,MyBatis提供了choose元素,它有点像Java中的switch语句

 <select id="queryBlogChoose" parameterType="map" resultType="com.Huiex.pojo.Blog">
     select * from mybatis.blog
     <where>
         <choose>
             <when test="views != null">
                 and views = #{views}
             </when>
             <when test="title != null">
                 and title = #{title}
             </when>
             <otherwise>
                 and author = #{author}
             </otherwise>
         </choose>
     </where>
 </select>

views != null成立时,执行select * from mybatis.blog where views = #{views}

views != null "title != null"都成立时,还是执行select * from mybatis.blog where views = #{views}

views != null不成立时, "title != null"成立时,执行select * from mybatis.blog where title != null

就是个choose(选择)语句

 @Test
 public void queryBlogChoose(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap<String, Object> map = new HashMap<>();
 ​
     map.put("views",1999);-------------------------------------结果是查询这个条件的sql
     map.put("author","author");---------------------------------这个被忽略
 ​
     List<Blog> blogList = mapper.queryBlogChoose(map);
     for (Blog blogs :
             blogList) {
         System.out.println(blogs);
     }
     sqlSession.close();
 }

set

不多说了

自动删去逗号

     <update id="updateBlog" parameterType="map">
         update blog
         <set>
             <if test="views != null">
                 views = #{views},
             </if>
             <if test="author != null">
                 author = #{author},
             </if>
         </set>
         where id=#{id}
     </update>

执行的sql为:update blog views = #{views} where id=#{id}

 @Test
 public void updateTest(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
     HashMap<String, Object> map = new HashMap<>();
 ​
     map.put("views",1111);
     map.put("id","111111");--------------------------------------修改id为111111的views
 ​
     int i = mapper.updateBlog(map);
     System.out.println(i);
 ​
     sqlSession.commit();
     sqlSession.close();
 }

foreach

collection属性:集合

item从集合遍历出来的值的名称

open属性:以什么开始

close属性:以什么开始

separator属性:分隔符

 <select id="queryBlogForeach" parameterType="map" resultType="com.Huiex.pojo.Blog">
     select * from mybatis.blog
     <where>
         <foreach collection="ids" item="id" open="(" close=")" separator="or">
             id = #{id}
         </foreach>
     </where>
 </select>

我们现在传递一一个万能的map ,这map 中可以存在一个集合!

 @Test
 public void foreachTest(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

在map中传递一个集合

     HashMap<String, Object> map = new HashMap<>();
     ArrayList<Integer> ids = new ArrayList<>();
     ids.add(1);
     ids.add(3);
     map.put("ids", ids);
     List<Blog> blogList = mapper.queryBlogForeach(map);
     for (Blog blogs :
             blogList) {
         System.out.println(blogs);
     }
     sqlSession.close();
 }

执行的sql语句为select * from mybatis.blog where (id = 1 or id = 3)

sql

  • 使用SQL标签抽取公共的部分

  • 在需要使用的地方使用Include标签引|用即可

  • 最好基于单表来定义SQL片段!

  • 不要存在where标签

<sql>标签 id属性为该sql的名称

 <sql id="if-views-title">
     
     <if test="views != null">
         and views = #{views}
     </if>
     <if test="title != null">
         and title = #{title}
     </if>
     
 </sql>

使用

<include>标签 refid属性为引用<sql>标签

 <select id="queryBlogWhere" parameterType="map" resultType="com.Huiex.pojo.Blog">
     select * from mybatis.blog
     <where>
         <include refid="if-views-title"></include>
     </where>
 </select>

日志

一个数据库操作,出现了异常,我们需要排错。使用日志

  • SLF4J

  • LOG4J [掌握]

  • LOG4J2

  • JDK_ LOGGING

  • COMMONS LOGGING

  • STDOUT_ LOGGING [ 掌握]

  • NO_ LOGGING

使用时需要在核心配置文件(mybatis-config.xml)配置

     <settings>
         <setting name="logImpl" value="这里写要配置的"/>
     </settings>

日志工厂

在核心配置文件(mybatis-config.xml)中

     <settings>
         <setting name="logImpl" value="STDOUT_LOGGING"/>
     </settings>

然后运行代码,返回视图中就会多出以下

就是封装好的JDBC操作的过程

Log4j

  • Log4j是Apache的一一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、

    GUI组件

  • 我们也可以控制每一条日志的输出格式;

  • 通过定义每-条日志信息的级别,我们能够更加细致地控制日志的生成过程。

  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码

导包

在pom.xml中导入依赖

         <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.12</version>
         </dependency>

配置Log4J的设置

在resources(资源)包中建立log4j.properties文件

 #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
 log4j.rootLogger=DEBUG,console,file
 ​
 #控制台输出的相关设置
 log4j.appender.console = org.apache.log4j.ConsoleAppender
 log4j.appender.console.Target = System.out
 log4j.appender.console.Threshold=DEBUG
 log4j.appender.console.layout = org.apache.log4j.PatternLayout
 log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
 ​
 #文件输出的相关设置
 log4j.appender.file = org.apache.log4j.RollingFileAppender
 log4j.appender.file.File=./log/Huiex.log
 log4j.appender.file.MaxFileSize=10mb
 log4j.appender.file.Threshold=DEBUG
 log4j.appender.file.layout=org.apache.log4j.PatternLayout
 log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
 ​
 #日志输出级别
 log4j.logger.org.mybatis=DEBUG
 log4j.logger.java.sql=DEBUG
 log4j.logger.java.sql.Statement=DEBUG
 log4j.logger.java.sql.ResultSet=DEBUG
 log4j.logger.java.sql.PreparedStatement=DEBUG

配置到项目

在核心配置文件(mybatis-config.xml)配置

     <settings>
         <setting name="logImpl" value="LOG4J"/>
     </settings>

分页

分页目的:减少数据的处理量

使用Limit分页

 select * from mybatis.user
 select * from mybatis.user limit 3 #查询从0行到第3行

Lombok

导入依赖

在pom.xml中

         
        <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <version>1.18.20</version>
        </dependency>

相关注解

 @Data:无参构造,get、 set、 tostring、 hashcode, equals
 ​
 @AllArgsconstructor:有参构造
 ​
 @NOArgsconstructor:无参构造

@Data+@AllArgsconstructor 只有有参构造(无参被覆盖了,可以自己写)

@Data+@NOArgsconstructor 只有无参

所以可以@Data+@AllArgsconstructor +@NOArgsconstructor即有无参又有有参

使用

1.在实体类上加注解(不多解释,懂得懂得)

 
package com.Huiex.pojo;
 ​
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 ​
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class User {
     private int id;
     private String name;
     private String pwd;
 }

2.也可以添加在属性上(鸡肋)

生成属性id的get方法

 public class User {
     @Getting
     private int id;
     private String name;
     private String pwd;
 }

缓存

一次查询的结果,给他暂存在一个可以直接取到的地方! -->内存:缓存

我们再次查询相同数据的时候,直接走缓存,就不用走数据库了

一级缓存

一级缓存也叫本地缓存: SqlSession

与数据库同-一次会话期间查询到的数据会放在本地缓存中

以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;

缓存失效的情况: 1.查询不同的东西 2.增删改操作,可能会改变原来的数据,所以必定会刷新缓存! 3.查询不同的Mapper.xml 4.手动清理缓存

一级缓存默认是开启的, 只在一次SqlSession中有效, 也就是拿到连接到关闭连接这个区间段

 @Test
 public void getUserById(){
     SqlSession sqlSession = MybatisUtils.getSqlSession();
     UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
     User userById1 = userMapper.getUserById(3);
     System.out.println(userById1);
 ​
     sqlSession.clearCache();-----------------------------------------------关闭缓存
         
     System.out.println("---------------");
     User userById2 = userMapper.getUserById(3);
     System.out.println(userById2);
 ​
 ​
     sqlSession.close();
 }

开启缓存之前

相同的sql语句,只执行一次连接和查询等等

关闭缓存后

相同的sql语句,仍分别从开始执行一次

二级缓存

二级缓存也叫全局缓存,一 级缓存作用域太低了,所以诞生了二级缓存

基于namespace级别的缓存,一个名称空间(Xxxmapper.xml),对应一个二级缓存;

工作机制

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;

  • 如果当前会话关闭了,这个会话对应的一-级缓存就没了;但是一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以从二级缓存中获取内容;

  • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。要启用全局的二 级缓存,只需要在你的SQL映射文件中添加一行:

步骤

1.开启全局缓存(默认开启) 在核心配置文件中的<settings>设置中

     <settings>
         <setting name="logImpl" value="LOG4J"/>
         <!--是否开启自动驼峰命名规则(camel case)映射-->
         <setting name="mapUnderscoreToCamelCase" value="true"/>
 --------------------------------------------------------------------------------------
         <!--显示的开启全局缓存-->
         <setting name="cacheEnabled" value="true"/>
     </settings>

2.在要使用二级缓存的Mapper中开启

 <mapper namespace="com.Huiex.dao.BlogMapper">
 ​
     <!--在当前Mapper. xmL中使用二级缓存-->
     <cache/>

3.

java.sql.SQLException: Value '0000-00-00' can not be represented as java.sql.Timestamp

的错误, 这是因为hibernate认为这个不是一个有效的时间字串。

而有效的日期格式为“ 0001-01-01 00:00:00.0 ”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值