SSM 框架之 Mybatis 整合

(2)新建一个普通 maven 项目作为父项目,并导入 sql 驱动,mybatis,junit 组件

  <!--导入依赖-->  <dependencies>      <!--mysql驱动-->      <dependency>          <groupId>mysql</groupId>          <artifactId>mysql-connector-java</artifactId>          <version>5.1.46</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>

(3)新建一个新组件作为子级项目,普通 maven 的 module

(4)添加配置文件

  • 在 src->main->resources 目录下新建 mybatis-config.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>    <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}"/> //数据库名字,默认root          <property name="password" value="${password}"/> //数据库密码,自己的数据库密码,一般为root        </dataSource>      </environment>    </environments>  </configuration>

2、编写 mybatis 工具类

MybatisUtils.java:

  //SqlSessionFactory --生产--> SqlSession  public class MybatisUtils {
   
         private static SqlSessionFactory sqlSessionFactory; //提升作用域      //获取工厂,固定代码      static {
   
             try {
   
                 String resource="mybatis-config.xml";              InputStream inputStream = Resources.getResourceAsStream(resource);              sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);          } catch (IOException e) {
   
                 e.printStackTrace();          }      }      //获取sqlSession      //SqlSession完全包含了面向对象数据库执行SQL命令所需的方法      public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession();}  }

3、编写相关代码

(1)实体类

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

(2)Dao 接口

  public interface UserDao {
   
         List<User> getUserList();  }

(3)xxxMapper.xml 配置文件

  • 接口的实现类要改为以 xxxMapper.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/Dao接口-->  <mapper namespace="com.wang.dao.UserDao">  <!--id:接口的方法,resultType:接口的返回值类型-->      <select id="getUserList" resultType="com.wang.pojo.User">          select * from mybatis.user where id = #{id}      </select>  </mapper>

每一个 Mapper.xml 文件都需要在 src->main->resources 目录下的 mybatis-config.xml 核心配置文件中注册:

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

4、测试

  public class UserDaoTest {
   
         @Test      public void test(){
   
             //获取SqlSession对象          SqlSession sqlSession = MybatisUtils.getSqlSession();          //获取mapper          UserDao mapper = sqlSession.getMapper(UserDao.class);          List<User> list = mapper.getUserList();          for (User u:list){
   
                 System.out.println(u);          }          //不推荐使用以下方式          /*          这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方    式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加 类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。          */          // List<User> list =  sqlSession.selectList("com.qian.dao.UserDao.getUserList");          // for (User user : list) {
   
             //     System.out.println(user);          // }                    //关闭SqlSession          sqlSession.close();      }  }

三、使用 Mybatis 实现 CRUD

1、Mapper 接口

public interface UserMapper {
   
       //查询全部用户    List<User> getUserList();    //根据id查询用户    User getUserById(int id);    //增加新的用户    boolean insertNewUser(User u);    //删除用户    boolean deleteUserById(int id);    boolean deleteUserByName(String name);    //修改用户    boolean updateUserById(User u);}

2、xxxMapper.xml 文件

<?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/Dao接口--><!--id:接口的方法,resultType:接口的返回值类型--><mapper namespace="com.wang.dao.UserMapper">    <select id="getUserList" resultType="com.wang.pojo.User">        select * from mybatis.user    </select>    <select id="getUserById" parameterType="int" resultType="com.wang.pojo.User">        select * from mybatis.user where id=#{id}    </select>    <!-- 对象中的属性,可以直接取出来用 -->    <insert id="insertNewUser" parameterType="com.wang.pojo.User">        insert into mybatis.user (id, name, pwd) VALUES (#{id},#{name},#{pwd})    </insert>    <delete id="deleteUserById" parameterType="int">        delete from mybatis.user where id=#{id}    </delete>    <delete id="deleteUserByName" parameterType="String">        delete from mybatis.user where name=#{name}    </delete>    <update id="updateUserById" parameterType="com.wang.pojo.User">        update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id}    </update></mapper>

3、测试类

public class UserDaoTest {
   
       @Test    public void test(){
   
           //获取SqlSession对象        SqlSession sqlSession = MybatisUtils.getSqlSession();        try{
   
               //获取mapper            UserMapper mapper = sqlSession.getMapper(UserMapper.class);                        // 查询全表            List<User> list = mapper.getUserList();            for (User u:list){
   
                   System.out.println(u);            }                        //根据id查询            User user = mapper.getUserById(1);            System.out.println(user);                        //插入新用户,注意:更新,插入,删除都需要提交事务            User user1 = new User(4,"李四","25615");            boolean isInserted = mapper.insertNewUser(user1);            sqlSession.commit();            //代码优化            if (mapper.insertNewUser(new User(4,"李四","25615"))) sqlSession.commit();                        //删除用户            if (mapper.deleteUserById(4))sqlSession.commit();            if (mapper.deleteUserByName("李四"))sqlSession.commit();                        //修改用户            if (mapper.updateUserById(new User(4,"王五","6849816")))sqlSession.commit();                    }finally {
   
               //关闭SqlSession            sqlSession.close();        }    }}

4、Map 的使用

map 可以代替任何的实体类,所以当我们数据比较复杂时,可以适当考虑使用 map 来完成相关工作。

(1)写方法

UserMapper.java:

  User getUser(Map<String,Object> map);  boolean addUser(Map<String,Object> map);

(2)写 sql

UserMapper.xml:

  <select id="getUser" parameterType="map" resultType="com.qian.pojo.User">      select * from mybatis.user where id=#{userId}  </select>  <insert id="addUser" parameterType="map">      insert into mybatis.user (id, name, pwd) VALUES (#{userId},#{userName},#{password})  </insert>

(3)测试

Test.java:

  @Test  public void test(){
   
         //获取SqlSession对象      SqlSession sqlSession = MybatisUtils.getSqlSession();      UserMapper mapper = sqlSession.getMapper(UserMapper.class);      Map<String, Object> map = new HashMap<String, Object>();      map.put("userId",5);      User user = mapper.getUser(map);      System.out.println(user);      map.put("userId",5);      map.put("userName","孙悟空");      map.put("password","123456");      if (mapper.addUser(map)) sqlSession.commit();      sqlSession.close();  }

5、模糊查询

方案一:在 Java 代码中拼串

string name = "%IT%";list<name> names = mapper.getUserByName(name);

UserMapper.xml:

<select id= "getUsersByName">	select * from user where name like #{name}</select>

方案二:在配置文件中拼接 1

Test.java:

string name = "IT";list<User> users = mapper.getUserByName(name);

UserMapper.xml:

<select id= "getUsersByName">    select * from user where name like "%"#{name}"%"</select>

方案三:在配置文件中拼接 2

Test.java:

string name = "IT";list<User> users = mapper.getUserByName(name);

UserMapper.xml:

<select id= "getUsersByName">    select * from user where name like "%${name}%"</select>

四、Mybatis 配置文件

1、核心配置文件

核心配置文件 mybatis-config.xml 包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文件的层次结构如下(顺序不能乱):

1.properties是一个配置属性的元素2.settings设置,mybatis最为复杂的配置也是最重要的,会改变mybatis运行时候的行为3.typeAliases别名(在TypeAliasRegistry中可以看到mybatis提供了许多的系统别名)4.typeHandlers 类型处理器(比如在预处理语句中设置一个参数或者从结果集中获取一个参数时候,都会用到类型处理器,在TypeHandlerRegistry中定义了很多的类型处理器)5.objectFactory 对象工厂(myabtis在构建一个结果返回的时候,会使用一个ObjectFactory去构建pojo)6.plugins 插件7.environments 环境变量    environment 环境变量       transactionManager 事务管理器       dataSource 数据源       databaseIdProvider 数据库厂商标识8.mappers 映射器

下面针对几个重要的元素 environments,properties,mappers,typeAliases,settings 进行讲解。

2、environments(环境)

environments 可以为 mybatis 配置多环境运行,将 SQL 映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过 default 指定),如果想切换环境修改 default 的值即可。

最常见的就是,生产环境和开发环境,两个环境切换必将导致数据库的切换。

<environments default="development"> <environment id="development">   <transactionManager type="JDBC">     <property name="..." value="..."/>   </transactionManager>   <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>      <environment id="product">       <transactionManager type="JDBC">         <property name="..." value="..."/>       </transactionManager>       <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>

  • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

  • 数据源是必须配置的。有三种内建的数据源类型:

type="[UNPOOLED|POOLED|JNDI]") - unpooled:这个数据源的实现只是每次被请求时打开和关闭连接。 - pooled:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来 , 这是一种使得并发 Web 应用快速响应请求的流行处理方式。 - jndi:这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

  • 数据源也有很多第三方的实现,比如 druid,hikari,dbcp,c3p0 等等…

  • 具体的一套环境,通过设置 id 进行区别,id 保证唯一!

  • 子元素节点:transactionManager - [ 事务管理器 ](以下两种事务管理器类型都不需要设置任何属性)

<!-- 语法 --><transactionManager type="[ JDBC | MANAGED ]"/>
  • 子元素节点:数据源(dataSource)

3、properties(属性)

数据库连接信息我们最好放在一个单独的文件中。

(1)在资源目录下新建一个 db.properties

driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/ssm?useSSL=true&useUnicode=true&characterEncoding=utf8username=rootpassword=root

(2)将 db.properties 文件导入核心配置文件

<configuration>   <!--导入properties文件-->   <properties resource="db.properties"/>
   <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></configuration>

4、mappers(映射器)

mappers 的存在就是要对写好的 mapper 和 xml 进行统一管理,要不然系统怎么知道我们写了哪些 mapper。

(1)常用引入方式

<mappers>    <!-- 使用相对于类路径的资源引用 -->    <mapper resource="com/wan/dao/userMapper.xml"/>    <!-- 面向注解时使用全类名 -->    <mapper class="com.wang.dao.AdminMapper"/></mappers>

(2)在 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"><mapper namespace="com.wang.mapper.UserMapper">   </mapper>

namespace 中文意思:命名空间,作用是 namespace 的命名必须跟某个接口同名,这才能找到实现绑定。

5、typeAliases(类型别名)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

在 mybatis-config.xml -> configuration 进行配置:

  <typeAliases>      <typeAlias type="com.wang.pojo.User" alias="user"></typeAlias>      <!-- 另一种方式:直接扫描一个包目录下的 -->      <package name="com.wang.pojo"/>  </typeAliases>

配置以后 xxxMapper.xml 的返回值(resultType)就可以替换为 resultType user

实体类较少的时候使用第一种,较多就直接扫描包目录

第二种也可以用注解 @Alias(“xxx”)给类起别名

6、settings(设置)

settings 能对我的一些核心功能进行配置,如懒加载、日志实现、缓存开启关闭等。

简单参数说明:

完整的 settings 元素,有很多可以配置的选项(可以自行了解):

<settings>    <!---->     <setting name="cacheEnabled" value="true"/>    <!---->     <setting name="lazyLoadingEnabled" value="true"/>    <!---->     <setting name="multipleResultSetsEnabled" value="true"/>     <setting name="useColumnLabel" value="true"/>     <setting name="useGeneratedKeys" value="false"/>     <setting name="autoMappingBehavior" value="PARTIAL"/>     <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>     <setting name="defaultExecutorType" value="SIMPLE"/>     <setting name="defaultStatementTimeout" value="25"/>     <setting name="defaultFetchSize" value="100"/>     <setting name="safeRowBoundsEnabled" value="false"/>     <setting name="mapUnderscoreToCamelCase" value="false"/>     <setting name="localCacheScope" value="SESSION"/>     <setting name="jdbcTypeForNull" value="OTHER"/>     <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/></settings>

五、Mybatis 日志配置

配置日志的一个重要原因是想在调试的时候能观察到 sql 语句的输出,能查看中间过程

1、标准日志实现

指定 MyBatis 应该使用哪个日志记录实现。如果此设置不存在,则会自动发现日志记录实现。STDOUT_LOGGING:标准输出日志。

 <configuration>      <properties resource="db.properties"/>      <settings>          <setting name="logImpl" value="STDOUT_LOGGING"/>      </settings>      ... ...  <configuration>

2、组合 logback 完成日志功能

(1)导入 log4j 的包

<dependency>    <groupId>ch.qos.logback</groupId>    <artifactId>logback-classic</artifactId>    <version>${logback.version}</version></dependency>

(2)log4j.properties 配置文件

<?xml version="1.0" encoding="UTF-8"?><configuration>
    <property name="pattern" value="%d{yyyy-MM-dd HH:mm:ss} %c [%thread] %-5level %msg%n"/>    <property name="log_dir" value="d:/logs" />
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">        <target>System.out</target>        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>    </appender>
    <appender name="file" class="ch.qos.logback.core.FileAppender">        <!--日志格式配置-->        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">            <pattern>${pattern}</pattern>        </encoder>        <!--日志输出路径-->        <file>${log_dir}/sql.log</file>    </appender>
    <root level="ALL">        <appender-ref ref="console"/>    </root>
    <logger name="mybatis.sql" level="debug" additivity="false">        <appender-ref ref="console"/>        <appender-ref ref="file"/>    </logger>
</configuration>

(3)setting 设置日志实现

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

六、resultMap 详解

如果数据库字段和实体的字段是一一对应,那么 MyBatis 会【自动映射】,但是如果不一致,比如一个叫 user 一个叫 username,那么就需要我们手动的建立一一映射的关系了。

(1)Java 实体类

public class User {
   
   
   private int id;  		    //id   private String name;   		//姓名,数据库为username   private String password;     //密码,一致      //构造   //set/get   //toString()}

(2)mapper 接口

//根据id查询用户User selectUserById(int id);

(3)mapper 映射文件

<select id="selectUserById" resultType="user">  select * from user where id = #{id}</select>

(4)测试与结果分析

Test.java:

@Testpublic void testSelectUserById() {
   
      UserMapper mapper = session.getMapper(UserMapper.class);   User user = mapper.selectUserById(1);   System.out.println(user);   session.close();}

结果:

User{id=1, name='null', password='123'}

查询出来发现 name 为空 . 说明出现了问题!

分析:

select * from user where id = #{id} 可以看做 select id,username,password from user where id = #{id}

mybatis 会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 利用反射去对应的实体类中查找相应列名的 set 方法设值,当然找不到 username

解决方案:

方案一:为列名指定别名 , 别名和 java 实体类的属性名一致 。

<select id="selectUserById" resultType="User">  select id , username as name ,password from user where id = #{id}</select>

方案二:使用结果集映射->ResultMap 【推荐】

<resultMap id="UserMap" type="User">   <!-- id为主键 -->   <id column="id" property="id"/>   <!-- column是数据库表的列名 , property是对应实体类的属性名 -->   <result column="username" property="name"/>   <result column="password" property="password"/></resultMap>
<select id="selectUserById" resultMap="UserMap">  select id , username , password from user where id = #{id}</select>

结论:

这个地方我们手动调整了映射关系,称之为【手动映射】。但如果不调整呢? MyBatis 当然会按照约定自动映射。当然约定的最基本的操作就是全部都一样,还有就是下划线和驼峰命名的自动转化。

<settings>    <!--开启驼峰命名规则-->    <setting name="mapUnderscoreToCamelCase" value="true"/></settings>

猜你喜欢

转载自blog.csdn.net/m0_69804655/article/details/130265126