1.什么是mybatis,有什么用?
- Mybatis 是一个半 ORM(对象关系映射)框架,它内部封装了 JDBC,开发时 只需要关注 SQL 语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。程序员直接编写原生态 sql,可以严格控制 sql 执行性 能,灵活度高。
- MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO 映射成数 据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
- 通过 xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中 sql 的动态参数进行映射生成最终执行的 sql 语句,最 后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。(从执行 sql 到返 回 result 的过程)
orm(Object Relational Mapping)
对象关系映射框架
实体类映射到一个数据库表,类中的属性映射到表的字段
(执行效率 高–>低) jdbc–>dbutils–>mybatis–>hibernate,jpa,mp
优点:
- 基于 SQL 语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任 何影响,SQL 写在 XML 里,解除 sql 与程序代码的耦合,便于统一管理;提供 XML 标签,支持编写动态 SQL 语句,并可重用。
- 与 JDBC 相比,减少了 50%以上的代码量,消除了 JDBC 大量冗余的代码,不 需要手动开关连接;
- 很好的与各种数据库兼容(因为 MyBatis 使用 JDBC 来连接数据库,所以只要 JDBC 支持的数据库 MyBatis 都支持)。
- 提供映射标签,支持对象与数据库的 ORM 字段关系映射;提供对象关系映射 标签,支持对象关系组件维护。
2.快速入门
- 创建java工程
- 添加mybatis与mysql数据库驱动包。
- 在mysql数据库下创建数据库表。
- 在entity包下创建数据库表对应的实体类。
- 在mapper包下创建实体类对应的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="userMapper">
<-- parameterType表示查询参数类型;resultType表示数据库查询结果的每行记录封装类型。-->
<select id="selectUserByKey" parameterType="int" resultType="User">
select * from tb_user where uid = #{uid}
</select>
</mapper>
- 在类路径下创建mybatis的xml核心配置文件,注意引入映射文件。
- 使用mybatis的核心api对象加载配置文件。
<?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>
<!--加载外部的properties资源文件-->
<properties resource="jdbc.properties">
</properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启事物不自动提交手动提交事物-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--配置该包下的所有类都有简写的名-->
<typeAliases>
<package name="com.javasm.entity"/>
</typeAliases>
<!--数据库环境-->
<environments default="dev">
<environment id="dev">
<!--事务管理器,使用JDBC的事务管理方法-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.Driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!--映射文件-->
<mappers>
<mapper resource="com\javasm\dao\userMapper.xml"/>
<mapper resource="com\javasm\dao\userMapper2.xml"/>
</mappers>
</configuration>
8.测试引入junit4
public class SqlSessionFactoryUtil {
private static SqlSessionFactory ssf=null;
static{
InputStream input = null;
try {
input = Resources.getResourceAsStream("mybatis-config.xml");
} catch (IOException e) {
e.printStackTrace();
}
ssf = new SqlSessionFactoryBuilder().build(input);
}
public static SqlSessionFactory getSqlSessionFactory(){
return ssf;
}
}
② 创建junit测试类
public class TestStart {
private static SqlSessionFactory ssf = null;
private SqlSession session = null;
@BeforeClass
public static void initFactory() {
ssf = SqlSessionFactoryUtil.getSqlSessionFactory();
}
@Before
public void openSession() {
session = ssf.openSession();
}
@Test
public void testGetUserById() throws IOException {
//SqlSession的selectOne方法的第一个参数是namespace.id组成的字符串,
//第二个参数是查询参数,且当前只能传入一个参数。
Object result = session.selectOne("userMapper.getUserById", 1);
System.out.println(result);
}
@After
public void closeSession() {
session.close();
}
@AfterClass
public static void closeFactory() {
ssf = null;
}
}
3.mybatis的核心对象(重要)
1.SqlSessionFactoryBuilder
:构建者模式应用,有build方法,用来构建复杂的单例的SqlSessionFactory对象
生命周期:用完即销毁.其生周期只存在于方法体内,可重用。
2.SqlSessionFactory
:工厂模式应用,与构建者的区别在于工厂生产N个对象.实现类:DefaultSqlSessionFactory,该对象中持有的DataSource
生命周期:全局唯一.放在web项目下理解,tomcat启动期间,只有一份Factory.单例
3.SqlSession
:数据库会话对象,实现类DefaultSqlSession.该对象内部有curd方法执行数据库表操作.(selectOne,selectList,insert,delete,update,getMapper),只有getMapper方法重要代理模式使用.
生命周期:每次数据库操作临时打开会话,用完关闭会话.需要创建它每个线程都有自己的 SqlSession 实例,SqlSession实例是不能被共享,也不 是线程安全的。
4.dao
接口的代理对象:
4.详细了解mybatis的核心文件配置
标签文件有先后顺序.dtd文件能看选后顺序
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
- properties标签,用来加载外部properties文件.
<properties resource="jdbc.properties">
</properties>
//引入
<dataSource type="POOLED">
<property name="driver" value="${jdbc.Driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
- environments标签,用来配置数据库连接信息.
- mappers标签,用来加载外部的xml映射文件
- settings标签,用来修改mybatis运行的默认行为.
<settings>
//展示自带的日志
<setting name="logImpl" value="STDOUT_LOGGING"/>
//数据库用连字符起字段名的忽略.把数据库中的_分割的列名,映射到实体类的驼峰属性名
<setting name="mapUnderscoreToCamelCase" value="true"></setting>
</settings>
- typeAliases:用来对指定包下的类自动起别名.要求整个项目下不能有同名的类
<typeAliases>
//具体类起别名,别名影响的是映射文件中的parameterType与resultType属性
<!--<typeAlias type="com.javasm.sys.entity.Sysuser" alias="sysuser"></typeAlias>-->
//该包下所有文件起别名,别名就是文件名
//不同的包不能起同名的类
<package name="com.javasm"></package>
</typeAliases>
5.掌握mybatis的映射文件(重要)
1.映射文件中常用标签
- select标签:用来执行select语句
<!--
parameterType:参数类型,可以写别名
resultType:把查询结果的一行记录封装的类型(map,实体对象,String,Double,Integer)
如果parameterType是简单类型的话,#{随便写}
如果parameterType是实体类,#{类的成员变量名}
如果parameterType是map,#{map的key}/params1,params2
-->
//简单类型下parameterType可以省略
<select id="selectUserByKey" parameterType="int" resultType="sysuser">
select * from sysuser where uid=#{uid}
</select>
- insert
<!--生成key模式 主键对应的属性名-->获得自增id
<!-- useGeneratedKeys="true" keyProperty="uid"-->
<insert id="addUser" parameterType="User" useGeneratedKeys="true" keyProperty="uid" >
insert into tb_user(uid, uname, uphone) values (#{uid},#{uname},#{uphone})
</insert>
@Test
public void addUser(){
User user = new User();
user.setUphone("5423423");
user.setUname("sdsa");
System.out.println(session.insert("userMapper.addUser", user));//返回受影响的行记录数
System.out.println(user.getUid());//返回刚刚新增的id
session.commit();//配置文件开启了事物
}
- update
<update id="updataUser" parameterType="user">
update tb_user set uname=#{uname},uphone=#{uphone} where uid=#{uid}
</update>
@Test
public void updataUser() {
User user = new User();
user.setUid(9);
user.setUname("赵鑫阳a");
System.out.println(session.update("userMapper.updataUser", user));//受影响行记录数
session.commit();
}
- delete
<delete id="delUserById" parameterType="int">
delete from tb_user where uid=#{uid}
</delete>
@Test
public void delUser() {
System.out.println(session.delete("userMapper.delUserById", 9));
session.commit();
}
2.#{}与${}使用
两者都是用来获取参数拼接sql.
#{}:mybatis内会使用PreparedStatement对象进行sql语句预编译,使用**?参数占位符**来传参,防止sql注入攻击.查询参数必须使用#{}
${}:不使用?占位符传参,而是字符串替换,就是把{}替换成变量的值,大多数用在对表格指定字段的排序使用,传入排序字段和排序规则(select * from user order by id)这个id是指定字段不能使数据/查询指定字段
6.getMapper
-
映射文件的namespace写为当前映射文件对应的接口类的全类名
<mapper namespace="com.javasm.dao.UserDao">
-
创建对应实体类的接口写方法和映射文件的id值相同
-
测试类调用
//传入dao接口的类对象,返回的是指定类的代理对象,映射文件的namespace必须是dao接口的全名
@Test
public void selectUserByKey() {
//传入一个接口对象返回一个接口的代理对象
UserDao mapper = session.getMapper(UserDao.class);
User user = mapper.selectUserByKey(4);//根据类名,方法名==namespace.id,底层仍然调用selectOne
System.out.println(user);
}
xml映射文件中的namespace不再随意,必须是mapper接口的名称(含包名)。
调用SqlSession会话对象方法时,通过getMapper方法返回mapper接口类型的对象是当前接口的代理对象
6.多参数操作
-
把多个参数封装到map
User selectUserByIdAndPhone(User user);
-
把多个参数封装到实体对象
User selectUserByIdAndPhone2(Map<String,Object> map);
-
在dao接口的方法中仍然保持多形参,形参前使用@Param注解,这种方式是mybatis底层把多个参数封装到map.map的key默认0,1,2…或者param1,param2…也可以通过@Param注解指定key
User selectUserByIdAndPhone3(@Param("uid_key") Integer uid,@Param("uphone_key") String phone);
7.模糊查询
- 在映射文件中的sql语句中使用%
<select id="selectUsersByPhone" parameterType="String" resultType="sysuser">
//idea环境下这个语句会报错但是不影响运行
select * from sysuser where uphone like "%"#{uphone}"%"
</select>
2.传入的字符串参数中带有%
@Test
public void test4_selectUsersByPhone() {
SysuserDao mapper = session.getMapper(SysuserDao.class);
List<Sysuser> sysusers = mapper.selectUsersByPhone("%2%");
System.out.println(sysusers);
}
8.查询结果返回map
对于复杂的多表级联查询,返回结果无法封装实体类,建议resultType=“map”,直接封装为map对象即可
1.两表联查询单个结果集
Map<String,Object> seletUserAndPowerById(Integer uid);
<select id="seletUserAndPowerById" parameterType="int" resultType="map">
select * from tb_user u,tb_power p where p.uid=u.uid and u.uid=#{uid}
</select>
@Test
public void seletUserAndPowerById() {
UserDao mapper = session.getMapper(UserDao.class);
Map<String, Object> map = mapper.seletUserAndPowerById(4);
System.out.println(map);
session.commit();
}
1.两表联查询多个结果集
List<Map<String,Object>> seletUserAndPowerById(Integer uid);
<select id="seletUserAndPowerById" parameterType="int" resultType="map">
select * from tb_user u,tb_power p where p.uid=u.uid and u.uid=#{uid}
</select>
@Test
public void seletUserAndPowerById() {
UserDao mapper = session.getMapper(UserDao.class);
List<Map<String, Object>> list = mapper.seletUserAndPowerById(4);
System.out.println(list);
session.commit();
}
注意点:
-
需要命名的地方,绝对不允许单个单词;
-
类的成员变量不建议long,不允许基本类型(Long数据,前端js代码不支持,数据丢失精度)
-
表字段名不允许u_name/uName(一个字母_单词)set,get方法名不规范,成员变量名不允许uName;成员变量名不允许is开头;
-
表中类型datetime,date,timestamp,实体类的成员变量类型,建议使用String;
-
23种gof设计模式
-
记忆框架的使用,
-
mybatis常见错的位置:
常见错误
- 映射文件忘记在配置文件引入.(配置文件中的mapping忘记写)
//Mapped Statements collection does not contain value for userMapper.selectUserByKey
- 映射文件中的namespace与id在写的时候写错
//Mapped Statements collection does not contain value for userMapper.selectUserByKeys
- 映射文件中的id重复了
//Mapped Statements collection already contains value for userMapper.selectUserByKey
- properties文件的配置不加载,key很可能写的单个单词
//url--->jdbc.url
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 |
true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods )。 |
true | false | false (在 3.4.1 及之前的版本中默认为 true) |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) |
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) |