mybatis
mybatis 文档:https://mybatis.org/mybatis-3/zh/
##maven:pom.xml
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.3</version> </dependency>
#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> <!-- 可以配置两个环境development test default=xxx--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/iqiyi?useSSL=false"/> <property name="username" value="root"/> <property name="password" value="howhy@123"/> </dataSource> </environment> </environments> <mappers> <!-- <mapper class="com.howhy.study.mapper.UserMapper"/>--> <package name="com.howhy.study.mapper"/> </mappers> </configuration>
##UserMapper.java接口 UserMapper.xml 文件名称路径必须一致
##UserMapper.java
public interface UserMapper { public User findUserById(Integer id); }
##UserMapper.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.howhy.study.mapper.UserMapper"> <select id="findUserById" resultType="com.howhy.study.domain.User"> select * from account where id = #{id} </select> </mapper>
##mybatis日志
##pom.xml
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.20</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency>
##logback.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- 配置文件修改时重新加载,默认true --> <configuration scan="true"> <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径--> <property name="CATALINA_BASE" value="**/logs"></property> <!-- 控制台输出 --> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder charset="UTF-8"> <!-- 输出日志记录格式 --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 第一个文件输出,每天产生一个文件 --> <appender name="FILE1" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- 输出文件路径+文件名 --> <fileNamePattern>${CATALINA_BASE}/aa.%d{yyyyMMdd}.log</fileNamePattern> <!-- 保存30天的日志 --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder charset="UTF-8"> <!-- 输出日志记录格式 --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 第二个文件输出,每天产生一个文件 --> <appender name="FILE2" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${CATALINA_BASE}/bb.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${CATALINA_BASE}/bb.%d{yyyyMMdd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="CUSTOM" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${CATALINA_BASE}/custom.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>${CATALINA_BASE}/custom.%d{yyyy-MM-dd}.log</fileNamePattern> <!-- keep 30 days' worth of history --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder charset="UTF-8"> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <!-- 设置日志输出级别 --> <root level="ERROR"> <appender-ref ref="CONSOLE" /> </root> <logger name="file1" level="DEBUG"> <appender-ref ref="FILE1" /> </logger> <logger name="file1" level="INFO"> <appender-ref ref="FILE2" /> </logger> <!-- 自定义logger --> <logger name="custom" level="INFO"> <appender-ref ref="CUSTOM" /> </logger> </configuration>
首先,如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性就 OK 了。例如,如果上面的 Author 表已经在 id 列上使用了自动生成,那么语句可以修改为:
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username,password,email,bio) values (#{username},#{password},#{email},#{bio}) </insert>
如果你的数据库还支持多行插入, 你也可以传入一个 Author
数组或集合,并返回自动生成的主键。
<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id"> insert into Author (username, password, email, bio) values <foreach item="item" collection="list" separator=","> (#{item.username}, #{item.password}, #{item.email}, #{item.bio}) </foreach> </insert>
对于不支持自动生成主键列的数据库和可能不支持自动生成主键的 JDBC 驱动,MyBatis 有另外一种方法来生成主键。
这里有一个简单(也很傻)的示例,它可以生成一个随机 ID(不建议实际使用,这里只是为了展示 MyBatis 处理问题的灵活性和宽容度):
<insert id="insertAuthor"> <selectKey keyProperty="id" resultType="int" order="BEFORE"> select CAST(RANDOM()*1000000 as INTEGER) a from SYSIBM.SYSDUMMY1 </selectKey> insert into Author (id, username, password, email,bio, favourite_section) values (#{id}, #{username}, #{password}, #{email}, #{bio}, #{favouriteSection,jdbcType=VARCHAR}) </insert>
在上面的示例中,首先会运行 selectKey 元素中的语句,并设置 Author 的 id,然后才会调用插入语句。这样就实现了数据库自动生成主键类似的行为,同时保持了 Java 代码的简洁。
selectKey 元素描述如下:
<selectKey keyProperty="id" resultType="int" order="BEFORE" statementType="PREPARED">
##mybatis 参数传递
1、#{} jdbc预编译的方式?传参 可以防止sql注入 ${} sql语句拼接的方式 有sql注入问题 一个参数 #{这里可以随便写} ${这里可以随便写}
2、多个参数:#{arg0} #{arg1} 或 #{param1} #{param2} 若dao层 参数没有注解@Param() 这两个方式都可以 若有注解@Param()只能使用#{param1} #{param2}
3、参数是javaBean或map 单个参数可以直接使用#{属性名} 或#{param1} 多个参数可以使用:#{param1} #{bean.属性} #{param1.属性}
4、参数是集合或数组 mybatis list会封闭成map {key:"list",value:"[1,2]"} 数组会封装成map {key:"array",value:"[1,2]"}如下
<select id="findUserByIds" resultType="com.howhy.study.domain.User"> select * from account where id = #{list[0]} or id = #{list[1]} </select>
<select id="findUserByIds" resultType="com.howhy.study.domain.User"> select * from account where id = #{array[0]} or id = #{array[1]} </select>
##ResultMap
<resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap> 然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)。比如: <select id="selectUsers" resultMap="userResultMap"> select user_id, user_name, hashed_password from some_table where id = #{id} </select>
Mybatis缓存
一级缓存:默认开启了
1、若关闭:localCacheScope=STATEMENT
2、缓存默认作用域是基于sqlSession的,一次数据库操作会话
3、缓存默认实现类PerpetualCache,使用map进行存储的key的值是hashcode+sqlid+sql语句+hashcode+开发环境
4、查询时就会缓存
缓存失效的情况:
1、不同的sqlSession会使一级缓存失效
2、同一个sqlSession不同的sql查询语句
3、同一个sqlSession和同样的sql查询语句但执行了其它的增删改的情况
4、手动清空缓存
二级缓存:默认也是开启的,但没有实现
1、作用域是全局的,应用级的
2、开启二级缓存 :<setting name="cacheEnabled" value="true"></setting>
3、在需要用到二级缓存的映射文件mapper.xml中加入<cache></cache>,基于mapper映射文件来实现缓存的,基于mapper映射文件命名空间来存储的
4、事务提交时才会缓存
缓存失效:
1、同一个命名空间进行增删改就会失效
先从二级缓存中取 若二级缓存没有再从一级缓存中取