SqlSessionFactory
SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,主要作用是创建SqlSession。
SqlSessionFactory是线程安全的,一旦被创建整个应用执行期间都会存在。如果多次的创建同一个数据库的SqlSessionFactory,那么数据库资源很容易被耗尽,因此在构建SqlSessionFactory实例时,一般使用单例模式。
// 创建SqlSessionFactory代码
InputStream inputStream = Resources.getResourceAsStream("配置文件位置");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession
SqlSession是应用程序与持久层之间执行交互操作的一个单线程对象,是线程不安全的。SqlSession使用完后,要及时关闭它。
SqlSession方法如下(了解即可,IDEA中可以点击ctrl+鼠标左键查看)
// 注:若使用mybatis的传统开发方式(即编写接口的实现类)需要用到以下方法,但不推荐使用此方式,推荐用xml或annotation
public interface SqlSession extends Closeable {
// statement是在配置文件中,
<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
// rowBounds:用于分页的参数对象
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
// 下面这些查询不常用,用到在学
<K, V> Map<K, V> selectMap(String var1, String var2);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3);
<K, V> Map<K, V> selectMap(String var1, Object var2, String var3, RowBounds var4);
<T> Cursor<T> selectCursor(String var1);
<T> Cursor<T> selectCursor(String var1, Object var2);
<T> Cursor<T> selectCursor(String var1, Object var2, RowBounds var3);
void select(String var1, Object var2, ResultHandler var3);
void select(String var1, ResultHandler var2);
void select(String var1, Object var2, RowBounds var3, ResultHandler var4);
//下面增删改(共六个方法)返回值是SQL语句所影响的行数
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String var1);
int delete(String var1, Object var2);
void commit();
void commit(boolean var1);
void rollback();
void rollback(boolean var1);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> var1);
Connection getConnection();
}
主要元素【注:必须按照以下顺序配置,否则会报错(可以缺,但不能乱)】
元素
<properties resource="路径"/>
元素
<settings>
<setting name="cacheEnabled" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
settings>
元素
typeAliases用于定义别名,减少全限定类名的冗余。
alias属性的属性值就是自定义的别名,可以代替com.li.domain.User使用在mybatis文件中的任何位置。如果alias属性省略,mybatis会默认将类名首字母小写后的名称作为别名。
<typeAliases>
<typeAlias alias="User" type="com.li.domain.User"/>
typeAliases>
元素
该元素可以配置多种数据源,即配置多种数据库。
environments标签的default属性用于指定默认的环境。environment是environments的子标签,可以定义多个(即配置多种数据库);transactionManager是environment的子标签,用于配置事务(有JDBC和MANAGED两种);dataSource也是environment的子标签,用于配置数据源(有UNPOOLED、POOLED常用、JNDI三种)。
样例
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
dataSource>
environment>
environments>
元素
该元素用于指定mybatis映射文件的位置,有以下四种配置方式
注意路径中的"/“与”.",一般前两种比较常用(资源用斜杠,类用点)
<mappers>
<mapper resource="mapper/UserMapper.xml"/>
<mapper class="mapper.UserMapper"/>
<mapper url="file:\\\D:\IDEA\code\mybatisCURD\src\main\resources\mapper\UserMapper.xml"/>
<package name="mapper"/>
mappers>
其他元素不太常用,略。等用到时再总结。
insert、delete、update、select元素【insert的元素中的特殊属性用法(其他元素略)】
resultMap
元素表示结果映射集,是MyBatis中最重要也是最强大的元素。它的主要作用是定义映射规则、级联的更新、定义类型转化器等。
包含的子元素如下
<resultMap id="" type="">
<constructor>
<idArg/>
<arg/>
constructor>
<id/>
<result/>
<association property=""/>
<collection property=""/>
<discriminator javaType="">
<case value="">case>
discriminator>
resultMap>
样例
<resultMap id="userResultMap" type="domain.User">
<id property="id" column="t_id"/>
<result property="username" column="t_username"/>
<result property="birthday" column="t_birthday"/>
<result property="sex" column="t_sex"/>
<result property="address" column="t_address"/>
resultMap>
<select id="findAllByResultMap" resultMap="userResultMap">
select * from t_user
select>
-- SQL脚本如下
CREATE TABLE `t_user` (
`id` int(11) NOT NULL auto_increment,
`username` varchar(32) NOT NULL COMMENT '用户名称',
`birthday` datetime default NULL COMMENT '生日',
`sex` char(1) default NULL COMMENT '性别',
`address` varchar(256) default NULL COMMENT '地址',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into `t_user`(`id`,`username`,`birthday`,`sex`,`address`)
values (41,'张三','2018-02-27 17:47:08','男','北京'),
(42,'小明','2018-03-02 15:09:37','女','北京金燕龙'),
(43,'小明','2018-03-04 11:34:34','女','北京金燕龙'),
(45,'李四','2018-03-04 12:04:06','男','北京金燕龙'),
(46,'王五','2018-03-07 17:37:26','男','北京'),
(48,'赵六','2018-03-08 11:44:00','女','北京修正');
依赖
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.21version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
实体类
package cn.pojo;
import lombok.ToString;
import java.util.Date;
@ToString
public class User {
private Integer id;
private String username;
private Date birthday;
private String six;
private String address;
}
持久层
package cn.dao;
import cn.pojo.User;
import java.util.List;
public interface UserDao {
List<User> findAll();
/**
* 注:在实际发开中,都是越简单越好,故不采用写Dao实现类的方式,使用xml或annotation都行。
* 虽然不推荐写Dao实现类,但是mybatis是支持写实现类的。
*/
}
配置
# resources/log4j.properties,把下面内容直接粘贴过去即可
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.dao.UserDao">
<select id="findAll" resultType="cn.pojo.User">
select *
from t_user
select>
mapper>
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.192.130:3306/test?serverTimezone=CTT"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="dao/UserDao.xml"/>
mappers>
configuration>
运行
package cn;
import cn.dao.UserDao;
import cn.pojo.User;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class App {
public static void main(String[] args) throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
//3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
UserDao userDao = session.getMapper(UserDao.class);
//5.使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
//6.释放资源
session.close();
inputStream.close();
}
/**
* 结果
* User(id=41, username=张三, birthday=Tue Feb 27 17:47:08 CST 2018, six=null, address=北京)
* User(id=42, username=小明, birthday=Fri Mar 02 15:09:37 CST 2018, six=null, address=北京金燕龙)
* User(id=43, username=小明, birthday=Sun Mar 04 11:34:34 CST 2018, six=null, address=北京金燕龙)
* User(id=45, username=李四, birthday=Sun Mar 04 12:04:06 CST 2018, six=null, address=北京金燕龙)
* User(id=46, username=王五, birthday=Wed Mar 07 17:37:26 CST 2018, six=null, address=北京)
* User(id=48, username=赵六, birthday=Thu Mar 08 11:44:00 CST 2018, six=null, address=北京修正)
*/
}
依赖
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.5version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.21version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>1.2.17version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.22version>
dependency>
实体类
持久层
package cn.dao;
import cn.pojo.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserDao {
@Select("select * from t_user")
List<User> findAll();
}
配置
log4j.properties 日志配置同上面 xml 方式,略
mybatis-config.xml 配置如下
DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="mysql">
<environment id="mysql">
<transactionManager type="JDBC">transactionManager>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.192.130:3306/test?serverTimezone=CTT"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
dataSource>
environment>
environments>
<mappers>
<mapper class="cn.dao.UserDao"/>
mappers>
configuration>
测试
package cn.dao;
import cn.pojo.User;
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.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
public class UserDaoTest {
@Test
public void findAll() throws IOException {
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = factory.openSession();
UserDao userDao = session.getMapper(UserDao.class);
List<User> users = userDao.findAll();
for (User user : users) {
System.out.println(user);
}
session.close();
inputStream.close();
}
/**
* 结果
* User(id=41, username=张三, birthday=Tue Feb 27 17:47:08 CST 2018, six=null, address=北京)
* User(id=42, username=小明, birthday=Fri Mar 02 15:09:37 CST 2018, six=null, address=北京金燕龙)
* User(id=43, username=小明, birthday=Sun Mar 04 11:34:34 CST 2018, six=null, address=北京金燕龙)
* User(id=45, username=李四, birthday=Sun Mar 04 12:04:06 CST 2018, six=null, address=北京金燕龙)
* User(id=46, username=王五, birthday=Wed Mar 07 17:37:26 CST 2018, six=null, address=北京)
* User(id=48, username=赵六, birthday=Thu Mar 08 11:44:00 CST 2018, six=null, address=北京修正)
*/
}
SQL脚本同上面的入门程序,略
#{}
与 ${}
的对比
#{} | ${} |
---|---|
一个占位符 | 一个sql串 |
自动进行java类型和jdbc类型转换 | 不进行jdbc类型转换 |
防止sql注入 | 无法防止sql注入 |
可以接收简单类型值或pojo属性值, 如果parameterType传输单个简单类型值, #{}括号中可以是value或其它名称。 |
可以接收简单类型值或pojo属性值, 如果parameterType传输单个简单类型值, ${}括号中只能是value |
select * from t_customer where username like concat('%',#{value},'%')
实体类
package cn.pojo;
import lombok.Data;
import java.util.Date;
@Data
public class User {
// 特意加个前缀user于列名不同,主要是用于测试resultMap映射
private Integer userId;
private String userName;
private String userAddress;
private String userSex;
private Date userBirthday;
}
package cn.pojo;
import lombok.Data;
@Data
public class FindPojo {
User user;
}
持久层
package cn.mapper;
import cn.pojo.FindPojo;
import cn.pojo.User;
import java.util.List;
/**
* mapper层即持久层,与以前的dao层一样。
* 也可以写dao.UserDao,配置文件写成UserDao.xml
* 但是mybatis提供的是mapper标签,因此用mapper居多,
* 也可以写成dao层,两者完全一样
*/
public interface UserMapper {
void addUser(User user);
void deleteUser(Integer id);
void updateUser(User user);
//包装类参数(注意xml中文件参数写法)
List<User> findByPojo(FindPojo pojo);
List<User> findAll();
}
配置
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.mapper.UserMapper">
<insert id="addUser" parameterType="cn.pojo.User">
INSERT INTO t_user (username, birthday, sex, address)
VALUES (#{userName}, #{userBirthday}, #{userSex}, #{userAddress})
insert>
<delete id="deleteUser" parameterType="Integer">
DELETE
FROM t_user
WHERE id = #{id}
delete>
<update id="updateUser" parameterType="cn.pojo.User">
UPDATE t_user
SET username = #{userName},
address = #{userAddress},
sex = #{userSex},
birthday = #{userBirthday}
WHERE id = #{userId}
update>
<select id="findByPojo" parameterType="cn.pojo.FindPojo" resultType="cn.pojo.User">
SELECT ID AS userId,
USERNAME AS userName,
BIRTHDAY AS userBirthday,
SEX AS userSex,
ADDRESS AS userAddress
FROM t_user
WHERE USERNAME LIKE #{user.userName}
select>
<select id="findAll" resultMap="userMap">
SELECT *
FROM t_user
select>
<resultMap id="userMap" type="cn.pojo.User">
<id property="userId" column="id"/>
<result property="userName" column="username"/>
<result property="userAddress" column="address"/>
<result property="userSex" column="sex"/>
<result property="userBirthday" column="birthday"/>
resultMap>
mapper>
测试
package cn.mapper;
import cn.pojo.FindPojo;
import cn.pojo.User;
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.Date;
import java.util.List;
public class UserMapperTest {
/**
* 注:增删改提交事务的方法都放在 @After public void destory()方法中
* 别没看全以为不用提交事务!
*/
private InputStream inputStream;
private SqlSession sqlSession;
private UserMapper userMapper;
@Before
public void init() throws IOException {
inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
sqlSession = factory.openSession();
userMapper = sqlSession.getMapper(UserMapper.class);
}
@After
public void destory() throws IOException {
//释放资源前提交事务,写在destory()内可以减少代码冗余,免得都写
sqlSession.commit();
//6.释放资源
sqlSession.close();
inputStream.close();
}
@Test
public void addUser() {
User user = new User();
user.setUserName("张良");
user.setUserBirthday(new Date());
user.setUserSex("男");
user.setUserAddress("郑州");
userMapper.addUser(user);
}
@Test
public void deleteUser() {
userMapper.deleteUser(48);
}
@Test
public void updateUser() {
User user = new User();
user.setUserName("孙悟空");
user.setUserBirthday(new Date());
user.setUserSex("男");
user.setUserAddress("水帘洞");
user.setUserId(46);
userMapper.updateUser(user);
}
@Test
public void findByPojo() {
FindPojo pojo = new FindPojo();
User user = new User();
user.setUserName("%小%");
pojo.setUser(user);
List<User> users = userMapper.findByPojo(pojo);
System.out.println(users);
}
@Test
public void findAll() {
List<User> users = userMapper.findAll();
for (User user : users) {
System.out.println(user);
}
}
}
常用注解
序号 | 注解 | 说明 |
---|---|---|
1 | @Insert | 增 |
2 | @Delete | 删 |
3 | @Update | 改 |
4 | @Select | 查 |
5 | @Result | 实现结果集封装 |
6 | @Results | 可以与@Result一起使用,封装多个结果集 |
7 | @ResultMap | 实现引用@Results定义的封装 |
8 | @One | 实现一对一结果集封装 |
9 | @Many | 实现一对多结果集封装 |
10 | @SelectProvider | 实现动态SQL映射 |
11 | @CacheNamespace | 实现注解二级缓存的使用 |
复杂注解映射说明
标签,该注解可以使用单个@Result,也可以使用@Result集合。
@Results(@Result()) 或 @Results({@Result(),@Result()})
和
标签,属性如下
标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
@Result(property="",column=" ",one=@One(select="")
标签,是多表查询的关键,在注解中用来指定子查询返回对象集合。
@Result(property="",column="",many=@Many(select=""))
代码
持久层
package cn.mapper;
import cn.pojo.FindPojo;
import cn.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 个人建议:短sql用注解,太长的sql写在xml文件中,否则方法上一大堆太丑
* 注:定义了@Results(id = "userMap")之后,以后可以用@ResultMap("userMap")进行引用,
* 例如下面的findByPojo方法可以不写SQL别名,添加注解@ResultMap("userMap")即可
* 定义@Results的方法(即findAll方法)无需使用,若是加上会编译报错!!!
*/
public interface UserMapper {
@Insert("INSERT INTO t_user (username, birthday, sex, address)" +
"VALUES (#{userName}, #{userBirthday}, #{userSex}, #{userAddress})")
void addUser(User user);
@Delete("DELETE FROM t_user WHERE id = #{id}")
void deleteUser(Integer id);
@Update("UPDATE t_user SET username = #{userName}, address = #{userAddress}," +
"sex = #{userSex}, birthday = #{userBirthday} WHERE id = #{userId}")
void updateUser(User user);
@Select("SELECT ID AS userId, USERNAME AS userName, BIRTHDAY AS userBirthday," +
"SEX AS userSex, ADDRESS AS userAddress FROM t_user WHERE USERNAME LIKE #{user.userName}")
List<User> findByPojo(FindPojo pojo); // 包装类参数
@Select("SELECT * FROM t_user")
@Results(id = "userMap",
value = {
@Result(property = "userId", column = "id"),
@Result(property = "userName", column = "username"),
@Result(property = "userAddress", column = "address"),
@Result(property = "userSex", column = "sex"),
@Result(property = "userBirthday", column = "birthday")
}
)
List<User> findAll();
}
配置 mybatis-config.xml
<mappers>
<mapper class="cn.mapper.UserMapper"/>
mappers>
测试