mybatis
mybatis基础写法
xml方式
依赖
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
映射文件配置
使用的配置标签
<mapper>
-
namespace:命名空间,为一个模块的唯一标识**(可随意命名),一般为dao层接口全域名**
-
<resultMap>
:可用于数据库列名和实体类字段名不同情况- id:唯一标识名
- type:返回的java对象类型
<id property="java属性名" column="展示的别名"/>
主键字段<result property="属性名" column="列名"/>
非主键 如果属性名和列名一致,可以不写
-
SQL语句
<select id="findById" resultMap="goodMap"> sql语句 </select>
例子
<?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">
<!-- 在全局xml中用 typeAliases配置别名之后 -->
<!-- 配置别名类型 -->
<mapper namespace="com.qf.dao.IGoodsDao">
<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
<resultMap id="goodMap" type="goods">
<!--主键字段-->
<id property="id" column="g_id"/>
<!--非主键字段 如果属性名和列名一致,可以不写-->
<result property="name" column="g_goods_name"/>
</resultMap>
<select id="findById" resultMap="goodMap">
select * from goods where g_id = #{id}
</select>
<select id="findAll" resultMap="goodMap">
select * from goods ;
</select>
<!-- 注意
在order by ,like 这种方式里,需要直接将字符串拼接的参数,需要使用 ${value}形式进行sql编写,$中必须使用value
除非在传值的时候,是通过map进行传值
-->
<select id="findAlls" resultType="com.qf.entity.Admin" parameterType="java.lang.String">
select * from admin order by ${value} desc
</select>
</mapper>
mybatis.xml全局配置
使用的标签
<configuration>
主配置文件,有两个主要节点:1、environments 2、mappers
<typeAliases>
配置别名,可用于对实体类进行别名配置,别名为实例类名-
<package name="实体类的javaBean包的全域名"/> (推荐)
注意:此处package只能放一个 -
<typeAlias type="对象全域名" alias="别名"> (不推荐)
-
<environments default="mysql">
环境配置,default:默认使用的环境-
<environment id="mysql">
环境,id:唯一标识-
<transactionManager type="JDBC"/>
配置事务类型 -
JDBC 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
-
MANAGED 它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期, 默认情况下它会关闭连接。
-
-
<dataSource type="POOLED">
配置数据源-
POOLED 使用连接池
-
UNPOOLED 不使用连接池,并发不高时可使用
-
JNDI
-
-
<mappers>
配置映射文件xml<mapper resource="xml全域名"/>
配置映射文件,指定映射配置文件的位置<mapper class="dao层接口的全域名"/>
配置类,注意:在resources目录中,也要有与对应的dao类有相同的路径,如:com/qf/dao/接口名<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<package name="dao层全路径"/>
配置包,只能有一个package
例子
<?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">
<!-- mybatis的主配置文件 -->
<configuration>
<!-- typeAliases 配置别名 -->
<typeAliases>
<!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写
<typeAlias type="com.qf.domain.User" alias="user"></typeAlias>-->
<!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
<package name="com.qf.entity"/>
</typeAliases>
<!-- 环境配置 -->
<environments default="mysql">
<!-- 配置mysql环境 -->
<environment id="mysql">
<!-- 配置事务类型 -->
<transactionManager type="JDBC"/>
<!-- 配置数据源 -->
<dataSource type="POOLED">
<!-- 配置数据源连接的4个属性 -->
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/shoppingmanage?characterEncoding=utf8&useSSL=false&serverTimezone=CTT"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
<mappers>
<mapper resource="com/qf/dao/IAdminDao.xml"/>
<mapper resource="com/qf/dao/IGoodsDao.xml"/>
</mappers>
<!-- <mappers>-->
<!-- 注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。 -->
<!-- 即:在resources目录中,也要有与对应的dao类有相同的路径,如:com.qf.dao-->
<!-- <mapper class="com.qf.dao.IAdminDao"/>-->
<!-- <package name="com.qf.dao"/>-->
<!-- </mappers>-->
</configuration>
测试
package com.qf.sqldemo.test;
import com.qf.sqldemo.dao.IAdminDao;
import com.qf.sqldemo.entity.Admin;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class SqlTest {
InputStream in ;
SqlSession session;
@Before // junit的注解
public void init() throws IOException {
in = Resources.getResourceAsStream("sqlSpringXml.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
session = factory.openSession();
}
@Test
public void test(){
IAdminDao adminDao = session.getMapper(IAdminDao.class);
Admin a = new Admin();
a.setAcctName("可");
a.setId(8);
List<Admin> list = adminDao.findAll(a);
for (Admin admin : list) {
System.out.println(admin);
}
}
@After
public void destory() throws IOException {
session.close();
in.close();
}
}
注意:如果是进行添加业务,则需要在openSession(true),加上true。
#和$的区别
-
#{}
表示一个占位符号通过#{}可以实现 preparedStatement向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果设定 parameterType,则传输设定的类型值,#{}括号中可以是 value 或其它名称。
-
${}
表示拼接 sql 串
通过${}
可以将传入parameterType类型的内容拼接在 sql中且不进行 jdbc 类型转换,${}
可以接收简单类型值或pojo 属性值,如果parameterType 传输单个简单类型值,${}括号中只能value。
<!-- 注意
在order by ,like 这种方式里,需要直接将字符串拼接的参数,需要使用 ${value}形式进行sql编写,$中必须使用value
除非在传值的时候,是通过map进行传值
-->
<select id="findAlls" resultType="com.qf.entity.Admin" parameterType="java.lang.String">
select * from admin order by ${value} desc
</select>
一对一查询
有时候在查询时,需要根据某个表关联一个表进行联表查询时,以一对一方式进行查询,即:只需要查询出两个关联的表的内容。
可通过数据库语言inner join 表名 on:内联,left join 表名 on:左外联,right join 表名 on:右外联,
outer join 表名 on:外联 方式进行拼接查询。
映射文件配置
使用的配置
<resultMap id="map名" type="查询表javaBean类型">
<id property="" column=""/>
配置主键<result property="属性名" column="列名"/>
非主键<association property="" javaType="">
用于配置实体类中对象的关联引用- 属性(常用)
- property:对应的主表对象类型属性名
- javaType:java中的对象类型
<id property="" column=""/>
配置主键<result property="属性名" column="列名"/>
非主键
- 属性(常用)
<resultMap id="map名" type="查询表javaBean类型"><!-- 从表 -->
<!--
以下属性必须配置,不论字段相同与否;如果不配置,打印时,相对应的字段将为null或0
如果查询时需要显示的字段,则必须配置;不需要的字段可不配置
-->
<id property="主键字段" column="更改后的字段名"/>
<result property="非主键字段" column="更改后的字段名"/>
<!-- 一对一的关系映射:配置封装JavaBean对象的内容
以下是主表,其中column是从表的外键,如果没有select,column可不写,写了无意义
-->
<association property="对应的主表对象" javaType="java中的对象类型" column="aid">
<!-- 同注意项1:-->
<id property="主键字段" column="更改后的字段名"/>
<result property="非主键字段" column="更改后的字段名"/>
</association>
</resultMap>
例子
resultMap配置
<resultMap id="listMap" type="card2"><!-- 打印的对象表 -->
<!--
以下属性必须配置,不论字段相同与否;如果不配置,打印时,相对应的字段将为null或0
如果查询时需要显示的字段,则必须配置;不需要的字段可不配置
-->
<id property="cid" column="cid"/>
<!-- <result property="aid" column="aid"/>-->
<result property="cname" column="cname"/>
<result property="cnum" column="cnum"/>
<!-- 一对一的关系映射:配置封装admin的内容
以下是关联表,其中column是从表的外键,如果没有select,column可不写,写了无意义
-->
<association property="admin" javaType="admin" column="aid">
<!--
以下属性必须配置,不论字段相同与否;如果不配置,打印时,相对应的字段将为null或0
如果查询时需要显示的字段,则必须配置;不需要的字段可不配置
-->
<id property="id" column="id"/>
<result property="acctName" column="acctName"/>
<result property="password" column="password"/>
<result property="crtTime" column="crtTime"/>
</association>
</resultMap>
SQL
<select id="findList" resultMap="listMap">
SELECT a.*,c.cid,c.cname,c.cnum FROM
admin a INNER JOIN card c ON a.id = c.aid;
</select>
注意:中和的column必须与SQL中的别名相同,如:
resultMap:
SQL:A.username as author_username
补充:
如果select中用的不是resultMap,而是resultType,:如果属性名和列名一致,可以不配置
一对多查询
一对多查询时,一般情况是一个JavaBean中,除了**本身对应表的字段,还存在其他表的引用对象的类,集合的引用。**即:主表实体中,包含从表实体的集合引用
使用的sql同样是通过关联查询方式。
映射文件配置
使用的配置
<resultMap id="map名" type="查询表javaBean类型">
<id property="" column=""/>
配置主键<result property="" column=""/>
非主键<collection property="" javaType="">
用于配置实体类中集合的关联引用- 属性(常用)
- select:从表对应的接口方法全域名
- colunm:从表依据查询的字段(会将值传递给从表)
- 属性(常用)
<?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="接口全域名">
<resultMap id="唯一标识" type="返回类型">
<id property="属性名" column="字段名"/>
<collection property="字段名" select="从表接口的方法全域名" column="从表依据查询的字段"/>
</resultMap>
<select id="方法名" resultMap="">
</select>
</mapper>
例子
AdminMapper.java
import com.qf.one2many.entity.Admin;
import java.util.List;
public interface AdminMapper {
List<Admin> findAll();
}
CardMapper.java
import com.qf.one2many.entity.Card;
import java.util.List;
public interface CardMapper {
List<Card> findAll();
}
AdminMapper.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.qf.one2many.dao.AdminMapper">
<resultMap id="adminMap" type="admin">
<id property="id" column="id"/>
<!-- 配置admin对象中card集合的映射-->
<collection property="cards" select="com.qf.one2many.dao.CardMapper.findAll" column="id"/>
</resultMap>
<!--配置查询所有-->
<select id="findAll" resultMap="adminMap">
SELECT a.*, c.cid, c.cname, c.cnum
FROM admin a
LEFT JOIN card c
ON a.id = c.aid
</select>
</mapper>
CardMapper.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.qf.one2many.dao.CardMapper">
<resultMap id="baseCardMapper" type="Card">
<id property="cid" column="cid"/>
</resultMap>
<select id="findAll" resultMap="baseCardMapper">
select * from card where aid = #{aid};
</select>
</mapper>
注解方式
使用到的注解
##### @Results
注解用于配置输出参数映射,其属性如下:
- id: 映射规则的唯一id,可以通过接口方法的**@ResultMap注解引用**.
- value: 存储@Result注解集合,配置每一个字段的映射规则.
@Result
注解用于配置单个字段的映射规则,(主键单独配置一个@Result),其属性如下:
- id: 表示当前字段是否为主键字段,默认值false.
- column: 数据库列名.
- property: pojo类属性名.
- one: 使用**@One注解引用其它pojo对象.**
- many**: 使用**@Many注解引用其它pojo对象集合**.
@One和@Many
注解用来引用其它pojo对象或pojo对象集合,其属性如下:
- select: 副查询方法的全类名.使用外层@Result的column属性作为参数
- fetchType: 加载模式,可选值:FetchType.LAZY表示延迟加载,FetchType.EAGER表示立即加载.
mybatis.xml全局配置
这里仅说mappers,其他配置与xml方式相同
<mappers>
方式一:
<!-- <package name="com.qf.one2many.dao"/> -->
方式二:
<mapper class="com.qf.one2many.dao.AdminMapper"/>
<mapper class="com.qf.one2many.dao.CardMapper"/>
</mappers>
AdminMapper.java
public interface AdminMapper {
@Select("SELECT a.*, c.cid, c.cname, c.cnum\n" +
"FROM admin a\n" +
"LEFT JOIN card c\n" +
"ON a.id = c.aid")
@Results(id = "aMapper",value = {
@Result(id = true, column = "id", property = "id"),
@Result(property = "cards", column = "id", many = @Many(select = "com.qf.one2many.dao.CardMapper.findAll"))
})
List<Admin> findAll();
--------------------------------------------------------------------
//@Select("select * from user where username=#{username} and password=#{password}")
//@Select("select * from user where username=#{arg0} and password=#{arg1}")
@Select("select * from user where username=#{param1} and password=#{param2}")
User login(String username, String password);
@Select("select * from user where username=#{username} and password=#{password}")
User login(@Param("username") String username, @Param("password") String password);
@Select("select * from user where uid = #{fdsa}")
User getUserByUid(int uid);
@Insert("insert into user values(null, #{username}, #{password}, #{age}, #{addr})")
int saveUser(User u);
}
CardMapper.java
public interface CardMapper {
@Select("select * from card where aid = #{aid}")
List<Card> findAll();
}
动态SQL
if 条件判断
<if test="条件"> sql </if>
choose
<choose> when/otherwise</choose>
<when test="条件"> sql </when>
<otherwise> sql </otherwise>
where
<where> sql </where>
:相当于sql语句中的where 1 = 1- 会自动去除多余的AND | OR
- 源于
<trim>
set(更新)
<set> <if test=""> sql </if> </set>
- 会自动去除多余的 , 号
- 源于
<trim>
trim
<trim prefix="WHERE" prefixOverrides="AND |OR " suffixOverrides="," prefix="SET"> sql </trim>
- prefix:前缀拼接
- prefixOverrides:去除前缀AND | OR
- suffixOverrides:去除后缀 , 号
foreach
<foreach collection="list" item="item" index="index" open="(" separator="," close=")">
- collection:遍历的对象
- item:遍历的参数值
- index:遍历的下标
- open:以(开始遍历
- close:以)结束遍历
- separator:分割符
<sql id="all">
select * from user
</sql>
<select id="selectAll" resultType="user">
<include refid="all"/>
</select>
<select id="selectUserByUid" resultType="user">
<include refid="all"/>
where uid = #{uid}
</select>
<select id="selectIf" resultType="user">
<include refid="all"/>
<where>
<if test="username != null">
username = #{username}
</if>
<if test="password != null">
and password = #{password}
</if>
</where>
</select>
<select id="selectIn" resultType="user">
<include refid="all" />
<where>
uid in
<foreach collection="ids" item="id" index="index" open="(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
延迟加载
https://blog.youkuaiyun.com/qq_35242910/article/details/78136435###
log4j日志
日志属于无侵入式的框架设计,即使用日志,不需要修改业务代码,不影响业务代码执行。
依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
spring-mybatis.xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
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>
<settings>
<!-- 配置日志为:LOG4J -->
<setting name="logImpl" value="LOG4J"/>
</settings>
</configuration>
log4j.properties
# 全局日志配置
# 日志级别:error(最高级), warn, info, debug(最低)
log4j.rootLogger=ERROR, stdout, F
# MyBatis 日志配置 log4j.logger.指定需要日志的路径,可以指定到方法,类,包
log4j.logger.com.qf.mapper.UsersMapper=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
# 文件输出
log4j.appender.F = org.apache.log4j.DailyRollingFileAppender
# 文件路径,下述路径为相对路径
log4j.appender.F.File =myproj.log
log4j.appender.F.Append = true
log4j.appender.F.Threshold = DEBUG
log4j.appender.F.layout=org.apache.log4j.PatternLayout
log4j.appender.F.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss}-[%p %F\:%L] %m%n
事务
pom.xml
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>com.springsource.org.aspectj.weaver</artifactId>
<version>1.6.8.RELEASE</version>
</dependency>
spring-mybatis.xml
<!--
配置事务管理器
-->
<bean id="dtx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds" />
</bean>
<!--
声明事务的实现方式
以这些关键字开头的方法分别设置事务的隔离级别以及出错后的操作
-->
<tx:advice transaction-manager="dtx" id="tx">
<tx:attributes>
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
<tx:method name="insert*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" rollback-for="Exception"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="mpt" expression="execution(* com.qfedu.service.*.*(..))" />
<aop:advisor advice-ref="tx" pointcut-ref="mpt" />
</aop:config>