【Java MyBatis基本问题】记录面试题宝典中自己不熟悉的MyBatis问题

18 篇文章 0 订阅
2 篇文章 0 订阅


参考文章:什么是MyBatis

学习之前,跟你们说点事情,有助于你能快速看完文章

很多同学对classpath这个东西不明白,在MyBatis中的classpath表示:main/javamain/resources第三方jar包的根目录

一、先应用再学习,代码示例

1. 第一个MyBatis程序

配置MyBatis

引入MyBatis的Jar包

<!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.21</version>
    </dependency>

  <!--mybatis-->
  <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.6</version>
  </dependency>

  <!--junit-->
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
  </dependency>

	<!--配置全局-->
		<!--在build中配置resource,来防止我们资源到处失败的问题-->
    <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>true</filtering>
            </resource>
        </resources>
    </build>

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>

    <environments default="development">

        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="com.mysql.cj.jdbc.Driver"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
        
    </environments>

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

MyBatis工具类

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //使用Mybatis第一步: 获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    //sqlSession 完全包含了面向数据库执行SQL命令所需的所有方法
    public static SqlSession getSqlsession() {
        // SqlSession sqlSession = sqlSessionFactory.openSession();
        return sqlSessionFactory.openSession();
    }
}

数据库搭建

CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`pwd` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user`(`id`,`name`,`pwd`) values (1,'小明','123456'),(2,'张三','abcdef'),(3,'李四','987654');

编程篇

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   private int id; 
   private String name;  
   private String pwd;  
}
public interface UserMapper {
   //查询全部用户
   List<User> getUserList();
}

编写xxxMapper接口的配置文件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">

<mapper namespace="com.mybatis.dao.UserMapper">
  <select id="getUserList" resultType="com.mybatis.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

测试接口

 @Test
    public void test(){

        SqlSession sqlSession = MybatisUtils.getSqlseesion();

        UserDao userdao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userdao.getUserList();

        for(User user : userList){
            System.out.println(user);
        }

        sqlSession.close();

    }

2. MyBatis整合Spring

配置MyBatis+Spring篇

<!--spring核心ioc-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>
<!--做spring事务用到的-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.5.RELEASE</version>
</dependency>
<!--mybatis依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.1</version>
</dependency>
<!--mybatis和spring集成的依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.9</version>
</dependency>
<!--阿里公司的数据库连接池-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.12</version>
</dependency>


<build>
    <!--目的是把src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
        <resource>
            <directory>src/main/java</directory><!--所在的目录-->
            <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    <!--指定jdk的版本-->
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

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>
    <!--settings:控制mybatis全局行为-->
    <settings>
        <!--设置mybatis输出日志-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <!--设置别名-->
    <typeAliases>
        <!--
            name:实体类所在的包名
            表示com.bjpowernode.domain包中的列名就是别名
            你可以使用Student表示com.bjpowenrode.domain.Student
            包下的所有类的类名则为别名
        -->
        <package name="com.SpringStudy.domain"/>
    </typeAliases>
    <!--
        一个mapper标签指定一个文件的位置。
        从类路径开始的路径信息
         target/classes(类路径)
     -->
    <mappers>
        <!--
         name:是包名, 这个包中的所有mapper.xml一次都能加载
       -->
       <package name="com.SpringStudy.dao"/>
    </mappers>
</configuration>

Spring配置文件spring-dao.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd

	<!--DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 dbcp druid
    我们这里使用Spring提供的JDBC:-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--关联mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
    </bean>

    <!--SqlSessionTemplate:就是我们使用的sqlSession-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
</beans>

数据库篇

数据库搭建

CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`pwd` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user`(`id`,`name`,`pwd`) values (1,'小明','123456'),(2,'张三','abcdef'),(3,'李四','987654');

编程篇

实体类User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   private int id;  //id
   private String name;   //姓名
   private String pwd;   //密码
}

实体类接口Mapper

public interface UserMapper {
   //查询全部用户
   List<User> getUserList();
}

xxxMapper接口的配置文件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">

<mapper namespace="com.mybatis.dao.UserMapper">
  <select id="getUserList" resultType="com.mybatis.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

UserMapper接口的UserMapperImpl 实现类,私有化sqlSessionTemplate

public class UserMapperImpl implements UserMapper {

    //我们的所有操作,都使用sqlSession来执行,在原来,现在都使用SqlsessionTemplate
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<User> selectUser() {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        return mapper.selectUser();
    }
}

将自己写的实现类,注入到Spring配置文件spring-dao.xml

    <bean id="userMapper" class="com.kuang.mapper.UserMapperImpl">
        <property name="sqlSession" ref="sqlSession"/>
    </bean>

测试篇

    @Test
    public void test () throws IOException {

        ApplicationContext context = new ClassPathXmlApplicationContext("spring-dao.xml");
        
        UserMapper userMapper = context.getBean("userMapper", UserMapper.class);
        for (User user : userMapper.selectUser()) {
            System.out.println(user);
        }
    }

3. SpringBoot整合MyBatis

配置篇

SpringBoot+MyBatis配置文件

<!--Springboot需要的依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

<!--Mybatis项目需要的依赖-->
    <!--mysqlq驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.12</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.4</version>
    </dependency>
    <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

<!--Springboot-Mybatis整合需要的依赖-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>


<build>
    <!--目的是把src/main/java目录中的xml文件包含到输出结果中。输出到classes目录中-->
    <resources>
        <resource>
            <directory>src/main/java</directory><!--所在的目录-->
            <includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
    <!--指定jdk的版本-->
    <plugins>
        <plugin>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

配置核心配置类application.yml:放在Resource文件夹下,SpringBoot会自己扫描到

spring:
  datasource:
    name: pro_man_sys_db
    url: jdbc:mysql://localhost:3306/pro_man_sys_db?serverTimezone=UTC
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
  resources:
    static-locations: classpath:/static,classpath:/resources,file:/root/uploadFiles

mybatis:
  type-aliases-package: com.shiliuzi.model
  mapper-locations: classpath:mapper/*.xml

数据库篇

CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(20) NOT NULL,
`name` varchar(20) DEFAULT NULL,
`pwd` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user`(`id`,`name`,`pwd`) values (1,'小明','123456'),(2,'张三','abcdef'),(3,'李四','987654');

编程篇
创建实体类User

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
   private int id;  //id
   private String name;   //姓名
   private String pwd;   //密码
}

创建实体类接口Mapper

@Mapper
public interface UserMapper {
   //查询全部用户
   List<User> getUserList();
}

配置Mapper.xml文件

<?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">
<!--configuration core file-->
<mapper namespace="com.guo.mapper.UserMapper">

    <select id="queryUserList" resultType="User">
    </select>
</mapper>

在这里插入图片描述

二、ORM(对象关系映射)

  • 简单:将MySQL的一张表映射成一个Java类
  • 易懂:MySQL数据库就被ORM转换为java程序员可以读懂的java类
  • 易用:ORM将sql查询全部封装成了编程语言中的函数

三、MyBatis整体流程,各组件的作用域和生命周期

执行流程
在这里插入图片描述

MyBatis组件
在这里插入图片描述

1. 配置解析

  • 可以添加配置信息的地方:mybatis-config.xml、Mapper.xml、MapperInterface注解信息。
  • Mybatis初始化过程中,会加载配置信息,并保存到Configuration对象中。
  • Configuration对象可以创建SqlSessionFactory对象,之后即可创建SqlSession对象执行数据库操作

2. SQL解析

  • SQL解析会根据运行时用户传入的实参,解析动态SQL中的标签,形成SQL模板,然后处理SQL模板中的占位符,用运行时的实参填充占位符,得到数据库真正可执行的SQL语句。

3. SQL执行
在这里插入图片描述

  • Executor:调用事务管理模块实现事务的相关控制,同时管理一级缓存和二级缓存
  • StatementHandler:SQL语句开始执行,依赖于ParameterHandler的实参绑定,然后执行SQL语句,从数据库中拿到ResultSet
  • ParameterHandler:进行SQL模板的实参绑定
  • ResultSetHandler:将ResultSet映射成Java对象返回给调用方

四、说说MyBatis-config.xml核心配置文件吧

主要说说接口和对应xml映射文件的位置问题,可以通过mapper映射标签解决
Mybatis中接口和对应的mapper文件不一定要放在同一个包下,如果放在一起的目的是为了Mybatis进行自动扫描,并且要注意此时Java接口的名称和mapper文件的名称要相同,否则会报异常,由于此时Mybatis会自动解析对应的接口和相应的配置文件,所以就不需要配置mapper文件的位置了。

如果接口和mapper文件不在同一个包下,就不能进行自动扫描解析了,需要对接口和文件分别进行配置。

<!--方式一:使用相对于类路径的资源引用-->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
</mappers>


<!--方式一:使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
</mappers>

<!--方式三:将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

五、讲讲xxxMapper.xml文件中的标签吧

如果童鞋们将上述的三个项目搭建认真看完并且总结了,我相信MyBatis在使用层面就没什么问题了,这里就再补充一下xxxMapper.xml文件的标签问题就好了。

1. CRUD标签

<!--对象中的属性,可以直接取出来-->
   <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
           select * from mybatis.user where id = #{id}
   </select>

    <insert id="addUser" parameterType="com.kuang.pojo.User">
        insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
    </insert>

    <update id="updateUser" parameterType="com.kuang.pojo.User">
        update mybatis.user set name=#{name},pwd=#{pwd}  where id = #{id} ;
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id = #{id};
    </delete>

2. parameterType传入参数
parameterType = 实体类
如果 User 类型的参数对象传递到了语句中,会查找 id、username 和 password 属性,然后将它们的值传入预处理语句的参数中。对传递语句参数来说,这种方式真是干脆利落。

<insert id="insertUser" parameterType="User">
  insert into users (id, username, password) values (#{id}, #{username}, #{password})
</insert>

parameterType = map

    <!--对象中的属性,可以直接取出来    传递map的key-->
    <insert id="addUser" parameterType="map">
        insert into mybatis.user (id, pwd) values (#{userid},#{passWord});
    </insert>
    @Test
    public void addUser2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);


        Map<String, Object> map = new HashMap<String, Object>();

        map.put("userid",5);
        map.put("passWord","2222333");

        mapper.addUser2(map);

        sqlSession.close();
    }

六、MyBatis剩下的问题,在这里总结一下

1. MyBatis的事务问题:CRUD需要提交事务!可以通过手动提交和自动提交完成:

  • 手动提交:sqlSession.commit();
  • 自动提交:sqlSessionFactory.openSession(true);

2. 属性名和字段名不一致:通过ReslutMap

但是MyBatis-plus底层会去识别数据库字段,然后遇到下划线就会转化为下一个字母的大写,也就是驼峰命名转化。

   <resultMap id="WaterSupplyProduction" type="com.ruoyi.domain.monitor.WaterSupplyProduction">
        <!-- 定义主键 ,非常重要。如果是多个字段,则定义多个id -->
        <!-- property:主键在pojo中的属性名 -->
        <!-- column:主键在数据库中的列名 -->
        <id property="id" column="id"/>

        <!-- 定义普通属性 -->
        <result property="areaName" column="area_name"/>
        <result property="factoryId" column="factory_id"/>
        <result property="monitorRecordId" column="monitor_record_id"/>
        <result property="riverLevel" column="river_level"/>
        <result property="riverTurbidity" column="river_turbidity"/>
        <result property="riverFlowRate" column="river_flow_rate"/>
        <result property="handledTurbidity" column="handled_turbidity"/>
        <result property="poolLevel" column="pool_level"/>
        <result property="factoryWaterTurbidity" column="factory_water_turbidity"/>
        <result property="factoryWaterPH" column="factory_water_pH"/>
        <result property="factoryWaterChlorine" column="factory_water_chlorine"/>
        <result property="factoryWaterRate" column="factory_water_rate"/>
        <result property="createTime" column="create_time"/>
    </resultMap>

    <select id="selectAll" resultMap="WaterSupplyProduction">
        select * from water_supply_production
    </select>

3. 使用注解开发项目:实际上就是将xxxMapper.xml与xxxMapper整合在一起

如果把xxxMapper.xml与xxxMapper整合在一起,那就应该把Mapper映射器位置改成xxxMapper接口位置

    <mappers>
        <mapper class="com.itheima.dao.UserMapper"></mapper>
    </mappers>
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},#{paswword})")
    int addUser(User user);
    
    @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
    int updateUser(User user);
    
    @Delete("delete from user where id=#{id}")
    int deleteUser(@Param("id") int id);
}

4. MyBatis的二级缓存

在MyBatis-config.xml核心配置文件开启二级缓存支持

<!-- 配置二级缓存 --> 
<settings> 
	<!-- 开启二级缓存的支持 --> 
 	<setting name="cacheEnabled" value="true"/> 
</settings>

在持久层接口中使用注解配置二级缓存

@CacheNamespace(blocking = true)
public interface UserMapper{

}

七、Hibernate与MyBatis的区别

1. 以Hibernate实例,实现ORM思想

参考文章:Hibernate入门这一篇就够了
参考文章:ORM框架原理与应用——实现ORM框架入门实例

配置环境和配置文件,我就不做了,这里主要是展示一下ORM思想的实现,具体配置在参考文章

  • User实体类
public class User {

    private int id;
    private String username;
    private String password;
    private String cellphone;

    //各种setter和getter
}
  • 编写对象映射User.hbm.xml
<!--在domain包下-->
<hibernate-mapping package="zhongfucheng.domain">

    <!--类名为User,表名也为User-->
    <class name="User"  table="user">

        <!--主键映射,属性名为id,列名也为id-->
        <id name="id" column="id">
            <!--根据底层数据库主键自动增长-->
            <generator class="native"/>

        </id>

        <!--非主键映射,属性和列名一一对应-->
        <property name="username" column="username"/>
        <property name="cellphone" column="cellphone"/>
        <property name="password" column="password"/>
    </class>
</hibernate-mapping>
  • 编写主配置文件hibernate.cfg.xml
<hibernate-configuration>
    <!-- 通常,一个session-factory节点代表一个数据库 -->
    <session-factory>

        <!-- 1. 数据库连接配置 -->
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.url">jdbc:mysql:///zhongfucheng</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">root</property>
        <!--
            数据库方法配置, hibernate在运行的时候,会根据不同的方言生成符合当前数据库语法的sql
         -->
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>


        <!-- 2. 其他相关配置 -->
        <!-- 2.1 显示hibernate在运行时候执行的sql语句 -->
        <property name="hibernate.show_sql">true</property>
        <!-- 2.2 格式化sql -->
        <property name="hibernate.format_sql">true</property>
        <!-- 2.3 自动建表  -->
        <property name="hibernate.hbm2ddl.auto">create</property>

        <!--3. 加载所有映射-->
        <mapping resource="zhongfucheng/domain/User.hbm.xml"/>

    </session-factory>
</hibernate-configuration>
  • 测试
public class App {
    public static void main(String[] args) {

        //创建对象
        User user = new User();
        user.setPassword("123");
        user.setCellphone("122222");
        user.setUsername("nihao");

        //获取加载配置管理类
        Configuration configuration = new Configuration();

        //不给参数就默认加载hibernate.cfg.xml文件,
        configuration.configure();

        //创建Session工厂对象
        SessionFactory factory = configuration.buildSessionFactory();

        //得到Session对象
        Session session = factory.openSession();

        //使用Hibernate操作数据库,都要开启事务,得到事务对象
        Transaction transaction = session.getTransaction();

        //开启事务
        transaction.begin();

        //把对象添加到数据库中
        session.save(user);

        //提交事务
        transaction.commit();

        //关闭Session
        session.close();
    }
}

2. Mybatis与hibernate的对比

参考文章

1. 开发速度的对比
就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。

比起两者的开发速度,不仅仅要考虑到两者的特性及性能,更要根据项目需求去考虑究竟哪一个更适合项目开发,比如:一个项目中用到的复杂查询基本没有,就是简单的增删改查,这样选择hibernate效率就很快了,因为基本的sql语句已经被封装好了,根本不需要你去写sql语句,这就节省了大量的时间,但是对于一个大型项目,复杂语句较多,这样再去选择hibernate就不是一个太好的选择,选择mybatis就会加快许多,而且语句的管理也比较方便。

2. 开发工作量的对比
Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。

3. sql优化方面
Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。

Hibernate HQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Log4j进行日志记录。

4. 对象管理的对比
Hibernate 是完整的对象/关系映射解决方案,它提供了对象状态管理(state management)的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的 JDBC/SQL 持久层方案中需要管理 SQL 语句,Hibernate采用了更自然的面向对象的视角来持久化 Java 应用中的数据。

换句话说,使用 Hibernate 的开发者应该总是关注对象的状态(state),不必考虑 SQL 语句的执行。这部分细节已经由 Hibernate 掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理

八、Mybatis插件

MyBatis 允许你在映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。


通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。


主要需要实现三个方法
intercept:在此实现自己的拦截逻辑,可从Invocation参数中拿到执行方法的对象,方法,方法参数,从而实现各种业务逻辑, 如下代码所示,从invocation中获取的statementHandler对象即为被代理对象,基于该对象,我们获取到了执行的原始SQL语句,以及prepare方法上的分页参数,并更改SQL语句为新的分页语句,最后调用invocation.proceed()返回结果。
plugin:生成代理对象;
setProperties:设置一些属性变量;


1. 定义插件

// ExamplePlugin.java
/**
 * @Intercepts 注解标记这是一个拦截器,其中可以指定多个@Signature
 * @Signature 指定该拦截器拦截的是四大对象中的哪个方法
 *      type:拦截器的四大对象的类型
 *      method:拦截器的方法,方法名
 *      args:入参的类型,可以是多个,根据方法的参数指定,以此来区分方法的重载
 */
@Intercepts({@Signature(
	type= Executor.class,		//指定组件
  	method = "update",		//指定组件中的方法
  	args = {MappedStatement.class,Object.class})})
	public class ExamplePlugin implements Interceptor {
  		public Object intercept(Invocation invocation) throws Throwable {
System.out.println("拦截器执行:"+invocation.getTarget());
        //目标对象
        Object target = invocation.getTarget();
        //获取目标对象中所有属性的值,因为ParameterHandler使用的是DefaultParameterHandler,因此里面的所有的属性都封装在其中
        MetaObject metaObject = SystemMetaObject.forObject(target);
        //使用xxx.xxx.xx的方式可以层层获取属性值,这里获取的是mappedStatement中的id值
        String value = (String) metaObject.getValue("mappedStatement.id");
        //如果是指定的查询方法
        if ("cn.cb.demo.dao.UserMapper.selectByUserId".equals(value)){
            //设置参数的值是admin_1,即是设置id=admin_1,因为这里只有一个参数,可以这么设置,如果有多个需要需要循环
            metaObject.setValue("parameterObject", "admin_1");
        }
        //执行目标方法
        return invocation.proceed();
  	}

    @Override
    public Object plugin(Object target) {
        //如果没有特殊定制,直接使用Plugin这个工具类返回一个代理对象即可
        return Plugin.wrap(target, this);
    }

	//设置一些属性,不重要。
    @Override
    public void setProperties(Properties properties) {
    }
}

2. 插件注入
这插件最终还是从IOC容器中获取的Interceptor[]这个Bean,因此我们只需要在配置类中注入这个Bean即可

/**
 * @Configuration:这个注解标注该类是一个配置类
 */
@Configuration
public class MybatisConfig{

    /**
     * @Bean : 该注解用于向容器中注入一个Bean
     * 注入Interceptor[]这个Bean
     * @return
     */
    @Bean
    public Interceptor[] interceptors(){
        //创建ParameterInterceptor这个插件
        ParameterInterceptor parameterInterceptor = new ParameterInterceptor();
        //放入数组返回
        return new Interceptor[]{parameterInterceptor};
    }
}

3. 测试

    @Test
    void contextLoads() {
      //传入的是1222
        UserInfo userInfo = userMapper.selectByUserId("1222");
        System.out.println(userInfo);

    }

4. 结果
测试代码传入的是1222,由于插件改变了入参,因此查询出来的应该是admin_1这个人。

5. 小结
简单的说,mybatis插件就是对ParameterHandler、ResultSetHandler、StatementHandler、Executor这四个接口上的方法进行拦截,利用JDK动态代理机制,为这些接口的实现类创建代理对象,在执行方法时,先去执行代理对象的方法,从而执行自己编写的拦截逻辑

九、MyBatis中的$和#有什么区别

 select ${arg0} from USER where userName = #{userName} and userPassword = #{userPassword};

使用#设置参数时:MyBatis会创建预编译的SQL语句,然后在执行SQL时MyBatis会为预编译SQL中的占位符(?)赋值。预编译的SQL语句执行效率高,并且可以防止注入攻击。
使用$设置参数时:MyBatis只是创建普通的SQL语句,然后在执行SQL语句时MyBatis将参数直接拼入到SQL里。这种方式在效率、安全性上均不如前者,但是可以解决一些特殊情况下的问题。例如,在一些动态表格(根据不同的条件产生不同的动态列)中,我们要传递SQL的列名,根据某些列进行排序,或者传递列名给SQL都是比较常见的场景,这就无法使用预编译的方式了。

十、MyBatis的缓存机制

1. 一级缓存
一级缓存基于sqlSession默认开启,不同的SqlSession之间的缓存数据区域是互相不影响的。当在同一个sqlSession中执行两次相同的sql语句时,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次查询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。

需要注意的是,如果SqlSession执行了DML操作(增删改),并且提交到数据库,MyBatis则会清空SqlSession中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。

2. 二级缓存
二级缓存的作用域是mapper的同一个namespace。不同的sqlSession两次执行相同的namespace下的sql语句,且向sql中传递的参数也相同,即最终执行相同的sql语句,则第一次执行完毕会将数据库中查询的数据写到缓存,第二次查询会从缓存中获取数据,不再去底层数据库查询,从而提高效率。

3. 设置二级缓存
在MyBatis 的全局配置settings 中有一个参数cacheEnabled,这个参数是二级缓存的全局开关,默认值是true ,初始状态为启用状态。

MyBatis 的二级缓存是和命名空间绑定的,即二级缓存需要配置在Mapper.xml 映射文件中。在保证二级缓存的全局配置开启的情况下,给Mapper.xml 开启二级缓存只需要在Mapper. xml 中添加如下代码:

<cache />
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值