Mybatis

一、工作原理

1)核心

原理详解:

        MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。

2)执行流程图

加载sqlmapconfig.xml,通过sqlsessionfactorybuilder,构建sqlsesionfactroy对象.由它构建sqlsession提供增删改查等操作数据库的方法.

1.sqlMapConfig.xml:mybatis全局配置文件,配置了数据源,事务等mybatis的运行环境,与spring整合后由spring的配置文件接管。mapper.xml映射文件(配置sql语句等)

2.sqlSessionFactory(会话工厂):创建sqlSession(根据配置文件创建)。

3.sqlSession:操作数据库(crud):是一个面向用户的接口

4.Executor(执行器):SqlSession内部通过该执行器操做数据库(是一个接口:分为基本执行器和缓存执行器)

5.mapped Statement:(底层封装对象):对操作数据库存储封装:包括sql语句,输入参数,输出结果类型进行封装。

mapped Statement的主要成员

StatementHandler 封装了JDBC Statement操作,负责对JDBCstatement 的操作,如设置参数等

ParameterHandler 负责对用户传递的参数转换成JDBC Statement 所对应的数据类型

ResultSetHandler  负责将JDBC返回的ResultSet结果集对象转换成List类型的集合

TypeHandler         负责java数据类型和jdbc数据类型(也可以说是数据表列类型)之间的映射和转换

MappedStatement MappedStatement维护一条<select|update|delete|insert>节点的封装

以上主要成员在一次数据库操作中基本都会涉及,在SQL操作中重点需要关注的是SQL参数什么时候被设置和结果集怎么转换为JavaBean对象的,这两个过程正好对应StatementHandler和ResultSetHandler类中的处理逻辑。

3)优缺点

优点:

1、灵活

2、解除sql与程序代码的耦合

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

4、提供对象关系映射标签

5、提供xml标签,支持编写动态sql。

缺点:

1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。

2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。

3、二级缓存机制不佳

使用jdbc开发时,和mybatis相比的不足

1,数据库连接,使用时就创建,不使用就释放,对数据库进行频繁连接开关和关闭,造成数据库资源浪费,影响数据库的性能

解决:使用数据库连接池管理数据库的连接

2,sql语句使用硬编码在java程序中,修改sql语句,就需要重新编译java代码,不利于系统维护

解决:把sql语句放在xml配置文件中,修改sql语句也不需要重新编译java代码

3,向预编译语句PreparedStatement中设置参数,对占位符位置和设置参数值,硬编码,修改sql语句也不需要重新编译java代码

解决:把sql语句和占位符设置参数值放在xml配置文件中

4,从result中遍历结果集数据时,存在硬编码,将获取表的字段进行硬编码

解决:将查询的结果集,自动映射成 java对象

和jdbc比较:

mybatis抽离出数据库的连接,关闭的操作.抽离了sql语句,并且可以自动的进行参数的设置,封装结果集.

2.mybatis跟hibante的比较, 优缺点.

1.hibernate是全自动,而mybatis是半自动。
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。
而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
2. hibernate数据库移植性远大于mybatis。
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(Oracle、MySQL等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
3. mybatis相比hibernate需要关心很多细节
hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。
4. sql直接优化上,mybatis要比hibernate方便很多
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。
而hibernate的sql很多都是自动生成的,无法直接维护sql;
虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;
hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。
总之写sql的灵活度上hibernate不及mybatis。

和hibernate比较:

- 性能:mybatis较hibernate高

- sql灵活性:mybatis较hibernate高

- 配置文件:mybatis较hibernate多(维护困难)

- 数据库的无关性:mybatis较hibernate低

4)编程步骤

1、加入jar包

2、创建conf.xml

3、创建xxxMapper.xml,要在conf.xml注册

4、建包bean,Mapper

5、测试

public staticvoid main(String[] args) throws IOException {

Stringresource = "conf.xml";

//加载mybatis 的配置文件(它也加载关联的映射文件)

Reader reader= Resources.getResourceAsReader(resource);

//构建sqlSession 的工厂

SqlSessionFactorysessionFactory = new SqlSessionFactoryBuilder().build(reader);

//创建能执行映射文件中sql 的sqlSession

SqlSessionsession = sessionFactory.openSession();

//映射sql 的标识字符串

Stringstatement = "com.atguigu.mybatis.bean.userMapper"+".selectUser";

//执行查询返回一个唯一user 对象的sql

User user =session.selectOne(statement, 1);

System.out.println(user);

}

CUD操作:

① 创建SqlSessionFactory

② 通过SqlSessionFactory创建SqlSession

③ 通过sqlsession执行数据库操作

④ 调用session.commit()提交事务

⑤ 调用session.close()关闭会话

二、sqlMapConfig.xml

SqlMapConfig,xml解析

文件中的配置项是有顺序的,按照官方图来配.

configuration

- properties

- settings

- typeAliases

- typeHandlers

- objectFactory

- plugins

- environments

* envioronment

* transactionManager

* dataSource

- databaseIdProvider

- mappers

 1.properties标签:

        可以引用一些properties的资源文件。注意:不建议在properties标签里添加属性,可能会覆盖掉其他相同名称的属性值。

2.Setting标签:

          配置全局参数:主要是跟Mybaties运行相关的一些参数

3.typeAliases

           别名定义。在mybatis中的resultType和parameterType的类型有可能是自定义的pojo类型,地址很长,不利于开发,可以使用别名定义。

           批量别名定义:在其中使用package标签,name为表名,别名为类名,首字母不区分大小写。

4.类型处理器

            jdbc类型与Java类型之间的相互转换,mybatis提供了许多转换类型,因此一般不需要我们手动配置。

5.mapper

            class属性加载的是通过mapper接口加载映射文件,但需要遵循一些规范:需要将mapper接口类名和mapper.xml映射文件名称一致,且在同一个目录当中。

            mapper批量加载:遵循上述规范,用package标签

<!-- resource:表示从classpath下加载 -->

   <properties resource="db.properties">

       <property name="jdbc.driver"value="com.mysql.jdbc.Driver"/>

   </properties>

settings: 全局参数设置

设置延迟加载:

   <settings>

       <!-- 开启延迟加载,默认值为true-->

        <settingname="lazyLoadingEnabled" value="true" />

       <!--设置积极的懒加载,默认值是true-->

       <setting name="aggressiveLazyLoading"value="false" />

   <settings>

typeAliases:类型别名

<!-- 自定义别名 -->

<typeAliases>

   <!-- type:指定java对象类型 -->

   <!-- alias:给java对象取得别名,对大小写不敏感-->

   <typeAlias type="com.aric.mybatis.po.User"alias="user"/>

   <!-- 扫描包的方式,别名就是包下类的类名,不区分大小写-->

   <package name="com.aric.mybatis.po"/>

</typeAliases>

<typeAliases>

       <typeAlias alias="Song" type="com.yrw.crawler.model.Song"/>

   </typeAliases>

<plugins>

           <plugininterceptor="com.github.pagehelper.PageHelper">

           <propertyname="dialect" value="mysql"/>

           </plugin>

</plugins>

<environmentsdefault="development">

        <environmentid="development">

            <transactionManagertype="JDBC" />

            <dataSourcetype="POOLED">

                <propertyname="driver" value="com.mysql.jdbc.Driver" />

                <propertyname="url" value="jdbc:mysql://localhost:3306/mybatis"/>

                <propertyname="username" value="root" />

                <propertyname="password" value="" />

            </dataSource>

        </environment>

    </environments>

mappers:

<mappers>

   <!-- resource:从classpath下加载sql映射文件-->

   <!-- <mapper resource="sqlmap/User.xml"/>

   <mapper resource="mapper/User.xml"/> -->

   <!-- 指定mapper接口的类路径 -->

   <!-- 要求:1.mapper接口 和sql的映射文件在同一个目录下,2.mapper接口的类名和映射文件的名称要一致-->

   <!-- <mapper class="com.aric.mybatis.mapper.UserMappser"/> -->

   <!--包扫描-->

   <package name="com.aric.mybatis.mapper" />

</mappers>

三、映射文件

mapper代理的方式(对原始dao的优化), 基于注解或者基于xml文档mapper,只需要写接口,不需要写实现类,实现类由mybatis框架自动创建.

使用步骤:

1.程序员需要编写mapper.xml文件

2.编写mapper接口需要依据规范:

                1. sql的映射文件中的namespace要和Mapper接口中的类路径(全限定名)一致

                2. sql的映射文件中的sql的id要和mapper接口中的方法的名称一致

                3. sql的映射文件中的parameterType要和mapper接口中的方法的参数类型一致

                4. sql的映射文件中的resultType要和mapper接口中的方法的返回值数据类型一致

3.获取自动生成的实现类对象

  sqlSession.getMapper(接口名.class);

<!-- namespace:命令空间,类似包-->

<mappernamespace="test">

   <!-- 添加用户 -->

   <!-- parameterType指定java对象,获取值时#{}中必须是java对象中的属性名 -->

       <!-- keyProperty:查询到的主键,放入到User对象中的id属性 -->

insert操作时,要注意主键 主键生成策略,要设置useGeneraterKey= true,和 keyProperty="id",指定哪个是主键

<insert id="addUser" parameterType="User" 
        useGeneratedKeys="true" keyProperty="id"> 
        insert into user(userName,userAge,userAddress)  
             values(#{userName},#{userAge},#{userAddress})  
    </insert>
 

   <!-- 删除用户 -->

   <delete id="deleteUserById"parameterType="int">

        delete from user where id = #{id}

   </delete>

   <!-- 更新用户 -->

   <update id="updateUserById"parameterType="user">

       update user set birthday=#{birthday},sex=#{sex},address=#{address} whereid=#{id}

</update>

<!-- id:代表sql语句的唯一标识-->

   <!-- resultType:查询结果集的类型 -->

   <!-- parameterType:输入参数的数据类型,通过parameterType接收参数,进行动态sql生成。运用ognl表达式-->

   <!-- #{id}:用于接收数据,代表一个占位符,表示将外部传递过来的数据映射到sql语句中 -->

   <!-- #{}中的变量可以是任意的(前提条件是:输入参数的数据类型是简单的类型) -->

   <select id="getUserById" parameterType="int"resultType="com.aric.mybatis.po.User" >

       select * from user where id=#{idd}

   </select>

   <!-- 如果查询的结果是列表,那么resultType只需指定列表中元素的类型 -->

   <select id="getUserByUsername"parameterType="String"resultType="com.aric.mybatis.po.User">

       <!-- ${value}表示sql串的拼接,${value}中变量必须是value(如果输入的是简单类型)

注意点

#{xxx}表示一个占位符,jdbc中的?通过#{xxx} 可以将外部传递过来映射到sql语句中,可以有效的防止sql注入.

xxx表示一个sql串的拼接,不可以有效防止sql注入.如果是{xxx},输入的参数类型是简单类型,那么${xxx}中的xxx必须是value.

-->

       select * from user where username like "%${value}%"

   </select>

<select id="selectUserOrders_details_items" resultMap="resultMap_user_orders_details_items">
    SELECT
        u.id AS user_id,
        u.username,
        ord.id AS order_id,
        ord.number,
        de.id AS detail_id,
        i.id AS item_id,
        i. NAME
    FROM
        USER u
    LEFT JOIN orders ord ON u.id = ord.user_id
    LEFT JOIN orderdetail de ON de.orders_id = ord.id
    LEFT JOIN items i ON de.items_id = i.id
</select>
</mapper>

输入映射

            自定义包装类型,可以将很多pojo类以及扩展类定义在包装类型中,根据需求而定

输出映射

  1.resultType

                ①:使用该属性映射,只有查询出来的列名与pojo属性名一致,才可以映射成功

                ②:如果查询出来的列名与pojo属性名全都不一致,则不会创建映射的pojo对象,但只要有一个列与pojo属性名称一致,就会创建pojo对象

 2.resultMap

          如果查询出来的列名与pojo属性名不一致却还要与pojo映射,可以使用resultMap

           首先要定义resultMap与pojo属性的对应关系

orm格式转换:通过设置resultMap和ResultType,将数据库中的记录转换为代码的bean对象。得到list或者对象。返回list,必须要配置resultMAp.

resultMap做复杂的映射配置(多表查询).

解决字段名与实体类属性名不相同的冲突

通过<resultMap>

<select id="selectOrderResultMap"parameterType="int" resultMap="orderResultMap">

select * from orders where order_id=#{id}

</select>

<resultMap type="_Order"id="orderResultMap">

<id property="id" column="order_id"/>

<result property="orderNo"column="order_no"/>

<result property="price"column="order_price"/>

</resultMap>

一对一查询

        使用association标签将关联的信息映射到单个Java对象中,使用collection将关联信息映射到对象的集合当中。

<!--

方式一:嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集

封装联表查询的数据(去除重复的数据)

select * from class c, teacher t wherec.teacher_id=t.t_id and c.c_id=1

-->

<select id="getClass"parameterType="int" resultMap="ClassResultMap">

select * fromclass c, teacher t where c.teacher_id=t.t_id and c.c_id=#{id}

</select>

<resultMap type="_Classes"id="ClassResultMap">

<idproperty="id" column="c_id"/>

<resultproperty="name" column="c_name"/>

<associationproperty="teacher" column="teacher_id"javaType="_Teacher">

<idproperty="id" column="t_id"/>

<resultproperty="name" column="t_name"/>

</association>

</resultMap>

<!--

方式二:嵌套查询:通过执行另外一个SQL 映射语句来返回预期的复杂类型

SELECT * FROM class WHERE c_id=1;

SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的teacher_id 的值

-->

<select id="getClass2"parameterType="int" resultMap="ClassResultMap2">

select * from class where c_id=#{id}

</select>

<resultMap type="_Classes"id="ClassResultMap2">

<idproperty="id" column="c_id"/>

<resultproperty="name" column="c_name"/>

<associationproperty="teacher" column="teacher_id"javaType="_Teacher"

select="getTeacher">

</association>

</resultMap>

<select id="getTeacher"parameterType="int" resultType="_Teacher">

SELECT t_idid, t_name name FROM teacher WHERE t_id=#{id}

</select>

映射一对多关系

<!--

方式一: 嵌套结果: 使用嵌套结果映射来处理重复的联合结果的子集

SELECT * FROM class c, teacher t,students WHERE c.teacher_id=t.t_id AND c.C_id=s.class_id AND c.c_id=1

-->

<select id="getClass3"parameterType="int" resultMap="ClassResultMap3">

select * fromclass c, teacher t,student s where c.teacher_id=t.t_id and c.C_id=s.class_idand c.c_id=#{id}

</select>

<resultMap type="_Classes"id="ClassResultMap3">

<idproperty="id" column="c_id"/>

<resultproperty="name" column="c_name"/>

<associationproperty="teacher" column="teacher_id"javaType="_Teacher">

<idproperty="id" column="t_id"/>

<resultproperty="name" column="t_name"/>

</association>

<!-- ofType指定students 集合中的对象类型 -->

<collectionproperty="students" ofType="_Student">

<idproperty="id" column="s_id"/>

<resultproperty="name" column="s_name"/>

</collection>

</resultMap>

<!--

方式二:嵌套查询:通过执行另外一个SQL 映射语句来返回预期的复杂类型

SELECT * FROM class WHERE c_id=1;

SELECT * FROM teacher WHERE t_id=1 //1 是上一个查询得到的teacher_id 的值

SELECT * FROM student WHERE class_id=1//1 是第一个查询得到的c_id 字段的值

-->

<select id="getClass4"parameterType="int" resultMap="ClassResultMap4">

select * fromclass where c_id=#{id}

</select>

<resultMap type="_Classes"id="ClassResultMap4">

<idproperty="id" column="c_id"/>

<resultproperty="name" column="c_name"/>

<associationproperty="teacher" column="teacher_id"javaType="_Teacher"

select="getTeacher2"></association>

<collectionproperty="students" ofType="_Student"column="c_id" select="getStudent"></collection>

</resultMap>

<select id="getTeacher2"parameterType="int" resultType="_Teacher">

SELECT t_idid, t_name name FROM teacher WHERE t_id=#{id}

</select>

<select id="getStudent"parameterType="int" resultType="_Student">

SELECT s_idid, s_name name FROM student WHERE class_id=#{id}

</select>

多对多映射

<!-- resultMap:定义查询用户关联查询订单关联查询订单明细及商品信息 -->
<resultMap type="user" id="resultMap_user_orders_details_items">
    <id column="user_id" property="id" />
    <result column="username" property="username"/>
    <!-- 一个用户对应多个订单 -->
    <collection property="orders" ofType="com.aric.mybatis.po.Orders">
        <id column="order_id" property="id" />
        <result column="number" property="number" />
        <!-- 一个订单对应多个订单明细 -->
        <collection property="orderdetail" ofType="com.aric.mybatis.po.OrderDetail">
            <id column="detail_id" property="id" />
            <!-- 一个订单明细对应一个商品 -->
            <association property="items" javaType="com.aric.mybatis.po.Items">
                <id column="item_id" property="id" />
                <result column="name" property="name" />
            </association>
        </collection>
    </collection>
</resultMap>

四、缓存

正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持

1. 一级缓存: 基于PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session.flush 或 close 之后,该Session 中的所有 Cache 就将清空。

2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于

其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。

3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了

C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

一级缓存:session(默认使用的)

1、同一个session,并且session没有close或者clearcache

2、查询条件一样

3、没有执行过增删改操作

二级缓存:Mapper(需要手动开启)

二级缓存的配置

1. 开启二级缓存中开关

   <!--二级缓存总开关-->

   <setting name="cacheEnabled" value="true">

2. 在mapper映射文件中开启二级缓存

<!--开启二级缓存,默认使用了PerpetualCache-->

<cache/>

<cache

eviction="FIFO" //回收策略为先进先出

flushInterval="60000" //自动刷新时间60s

size="512" //最多缓存512 个引用对象

readOnly="true"/> //只读

3. 禁止使用缓存

useCache=”false”

4. 刷新缓存

select语句默认是false,增删改语句默认是true

flushCache="true"

五、动态SQL

1.主要是where标签与if标签的综合使用,进行灵活的判断后动态拼接sql语句,where标签会自动将第一个and去掉。

2.定义sql片段:可以将相同的sql片段提取出来,这样其他的语句就可以引用该sql,在mapper.xml文件中单独使用sql标签定义。注意:相对于单表定义可重用性才高,不要在其中定义where标签。引用sql片段用include标签。

3.foreach标签可以遍历组装sql语句

collection属性为集合属性名

items为集合属性名称

open为拼接开始语句,close为拼接结束语句,separator为拼接集合属性的连接sql


MyBatis中用于实现动态SQL的元素主要有:
1、if和where
2、choose(when,otherwise)
3、trim
4、set
5、foreach
下面将逐一进行介绍。

if

<!-- 根据用户id和用户名称查询,需要进行判断,如果id为空,就以名称查询,如果名称为空,就以id查询,如果都为空,查询所有 -->
<select id="getUserByIdOrUsername" parameterType="user" resultType="user">
    select * from user 
    <!-- where:可以去掉多余的and,拼接where条件 -->
    <where>
        <if test="id != null">
            and id=#{id}
        </if>
        <if test="username != null and username !=''">
            and username like '%${username}%'
        </if>
    </where>
</select>

choose, when, otherwise

 <select id="findActiveBlogLike" resultType="Blog">
        SELECT * FROM BLOG WHERE state = ‘ACTIVE’
        <choose>
            <when test="title != null">
                AND title like #{title}
            </when>
            <when test="author != null and author.name != null">
                AND author_name like #{author.name}
            </when>
            <otherwise>
                AND featured = 1
            </otherwise>
        </choose>
    </select>

trim, where, set

<!-- 更新用户 -->
<update id="updateUser" parameterType="user">
    update user
    <!-- set:更新并且可以去掉多余的"," -->
    <set>
        <if test="address != null and address != ''">
            address =#{address},
        </if>
        <if test="sex != null and sex != ''">
            sex =#{sex},
        </if>
        <if test="username != null and username != '' ">
            username =#{username}
        </if>
    </set>
    where id=#{id}
</update>
 
<!--去掉多余的前缀-->
<trim prefix="WHERE" prefixOverrides="AND |OR ">
    ...
</trim>
 
<!--去掉多余的后缀-->
<trim prefix="SET" suffixOverrides=",">
    ...
</trim>

foreach

<!-- 查询id在一个范围的用户 -->
<select id="getUserListByForEach" parameterType="QueryVo" resultType="user">
    select * from user 
    <where>
        <!-- collection:queryvo中的集合属性ids -->
        <!-- open:表示开始的sql串 -->
        <!-- close:表示结束的sql串 -->
        <!-- item:要遍历的变量 -->
        <!-- separator:循环遍历时,指定分割的字符 -->
        <foreach collection="ids" open="id in(" close=")" item="id" separator=",">
            `#{id}`
        </foreach>
    </where>
</select>

六、Mybatis整合spring

1. 创建工程 
2. 加入jar spring的包 mybatis的包依赖包 数据库驱动 数据连接池 整合包 日志包 
3. mybatis配置文件

   <configuration>

       <!--全部交给spring管理,但是文件必须存在-->

   </configuration>

4. spring的配置文件

<!-- 配置db.properties数据源 -->

       <context:property-placeholderlocation="classpath:db.properties" />

       <!-- 配置数据库连接池 -->

       <bean id="dataSource"class="org.apache.commons.dbcp.BasicDataSource">

            <!-- 配置连接池属性 -->

            <propertyname="driverClassName" value="${jdbc.driver}" />

            <property name="url"value="${jdbc.url}" />

            <propertyname="username" value="${jdbc.username}" />

            <propertyname="password" value="${jdbc.password}" />

            <propertyname="maxActive" value="10" />

            <propertyname="maxIdle" value="5" />

       </bean>

 

       <!-- 配置sqlSessionFactory -->

       <bean id="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">

            <!-- 注入mybatis配置文件-->

            <propertyname="configLocation"value="classpath:mybatis/SqlMapConfig.xml"></property>

            <!-- 注入连接池 -->

            <propertyname="dataSource" ref="dataSource"></property>

       </bean>

       <!-- mapper扫描方式生成代理对象 -->

       <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

            <!-- 指定扫描的包 :1.自动批量生成代理对象(接口的类名首字母小写) 2.加载mapper映射文件 -->

            <propertyname="basePackage"value="com.aric.mybatis.mapper"></property>

<propertyname="sqlSessionFactory" ref="sqlSessionFactory" />

       </bean>

<!-- 4. 事务管理 : DataSourceTransactionManager-->

    <beanid="txManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <propertyname="dataSource" ref="dataSource" />

    </bean>

    <!--5. 使用声明式事务 -->

    <tx:annotation-driventransaction-manager="txManager" />

</beans>

5、通过逆工程生成POJO、Mapper和xxxMapper.xml

6. 数据库、日志的配置文件 


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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值