package com.enjoylearning.mybatis;
//STEP 1. 导入sql相关的包
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.enjoylearning.mybatis.entity.TUser;
public class JdbcDemo {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true";
// Database credentials
static final String USER = "root";
static final String PASS = "root";
@Test
public void QueryStatementDemo() {
Connection conn = null;
Statement stmt = null;
List<TUser> users = new ArrayList<>();
try {
// STEP 2: 注册mysql的驱动
Class.forName("com.mysql.jdbc.Driver");
// STEP 3: 获得一个连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// STEP 4: 创建一个查询
System.out.println("Creating statement...");
stmt = conn.createStatement();
String userName = "lison";
String sql="SELECT * FROM t_user where user_name='"+userName+"'";
ResultSet rs = stmt.executeQuery(sql);
System.out.println(stmt.toString());
// STEP 5: 从resultSet中获取数据并转化成bean
while (rs.next()) {
System.out.println("------------------------------");
// Retrieve by column name
TUser user = new TUser();
// user.setId(rs.getInt("id"));
// user.setUserName(rs.getString("user_name"));
user.setRealName(rs.getString("real_name"));
user.setSex(rs.getByte("sex"));
user.setMobile(rs.getString("mobile"));
user.setEmail(rs.getString("email"));
user.setNote(rs.getString("note"));
System.out.println(user.toString());
users.add(user);
}
// STEP 6: 关闭连接
rs.close();
stmt.close();
conn.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (stmt != null)
stmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
System.out.println("-------------------------");
System.out.println("there are "+users.size()+" users in the list!");
}
@Test
public void QueryPreparedStatementDemo() {
Connection conn = null;
PreparedStatement stmt = null;
List<TUser> users = new ArrayList<>();
try {
// STEP 2: 注册mysql的驱动
Class.forName("com.mysql.jdbc.Driver");
// STEP 3: 获得一个连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// STEP 4: 创建一个查询
System.out.println("Creating statement...");
String sql;
sql = "SELECT * FROM t_user where user_name= ? ";
stmt = conn.prepareStatement(sql);
stmt.setString(1, "lison");
System.out.println(stmt.toString());//打印sql
ResultSet rs = stmt.executeQuery();
// STEP 5: 从resultSet中获取数据并转化成bean
while (rs.next()) {
System.out.println("------------------------------");
// Retrieve by column name
TUser user = new TUser();
// user.setId(rs.getInt("id"));
// user.setUserName(rs.getString("user_name"));
user.setRealName(rs.getString("real_name"));
user.setSex(rs.getByte("sex"));
user.setMobile(rs.getString("mobile"));
user.setEmail(rs.getString("email"));
user.setNote(rs.getString("note"));
System.out.println(user.toString());
users.add(user);
}
// STEP 6: 关闭连接
rs.close();
stmt.close();
conn.close();
} catch (SQLException se) {
// Handle errors for JDBC
se.printStackTrace();
} catch (Exception e) {
// Handle errors for Class.forName
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (stmt != null)
stmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
System.out.println("-------------------------");
System.out.println("there are "+users.size()+" users in the list!");
}
@Test
public void updateDemo(){
Connection conn = null;
PreparedStatement stmt = null;
try {
// STEP 2: 注册mysql的驱动
Class.forName("com.mysql.jdbc.Driver");
// STEP 3: 获得一个连接
System.out.println("Connecting to database...");
conn = DriverManager.getConnection(DB_URL, USER, PASS);
// STEP 4: 启动手动提交
conn.setAutoCommit(false);
// STEP 5: 创建一个更新
System.out.println("Creating statement...");
String sql = "update t_user set mobile= ? where user_name= ? ";
stmt = conn.prepareStatement(sql);
stmt.setString(1, "186995587411");
stmt.setString(2, "lison");
System.out.println(stmt.toString());//打印sql
int ret = stmt.executeUpdate();
System.out.println("此次修改影响数据库的行数为:"+ret);
// STEP 6: 手动提交数据
conn.commit();
// STEP 7: 关闭连接
stmt.close();
conn.close();
} catch (SQLException se) {
// Handle errors for JDBC
try {
conn.rollback();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
se.printStackTrace();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
} finally {
// finally block used to close resources
try {
if (stmt != null)
stmt.close();
} catch (SQLException se2) {
}// nothing we can do
try {
if (conn != null)
conn.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
}
}
1.PreparedStatement与Statement区别:
1)PreparedStatement执行查询后,第一次查询会预编译,数据库会对该语句的执行进行缓存,包括执行计划,包括结果等,以后查询速度很快。(mybatis默认)
Statement每次查询,都一样。
2)PreparedStatement防止sql注入。
2.ORM是什么?
对象关系映射(ORM),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换;
也就是说,java代码中的对象与数据库中的数据一一对应。
3.hibernate与mybatis的区别:
hibernate仅支持全表映射(不能只查询某几个字段)
4示例操作:
package com.enjoylearning.mybatis.entity;
public class TUser {
private Integer id;
private String userName;
private String realName;
private Byte sex;
private String mobile;
private String email;
private String note;
private Integer positionId;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public Byte getSex() {
return sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public Integer getPositionId() {
return positionId;
}
public void setPositionId(Integer positionId) {
this.positionId = positionId;
}
@Override
public String toString() {
return "TUser [id=" + id + ", userName=" + userName + ", realName="
+ realName + ", sex=" + sex + ", mobile=" + mobile + ", email="
+ email + ", note=" + note + ", positionId=" + positionId + "]";
}
}
package com.enjoylearning.mybatis.mapper;
import com.enjoylearning.mybatis.entity.TUser;
public interface TUserMapper {
TUser selectByPrimaryKey(Integer id);
}
<?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.enjoylearning.mybatis.mapper.TUserMapper">
<select id="selectByPrimaryKey" resultType="com.enjoylearning.mybatis.entity.TUser" parameterType="java.lang.Integer">
select
id,
user_name ,
real_name ,
sex,
mobile,
email,
note,
position_id positionId
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
</mapper>
<?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 resource="db.properties" />
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!--配置environment环境 -->
<environments default="development">
<!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="UNPOOLED">
<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>
<!-- 映射文件,mapper的配置文件 -->
<!-- <mappers>
直接映射到相应的mapper文件
<mapper resource="sqlmapper/TUserMapper.xml" />
</mappers> -->
<mappers>
<mapper class="com.enjoylearning.mybatis.mapper.TUserMapper" />
</mappers>
</configuration>
jdbc_driver=com.mysql.jdbc.Driver
jdbc_url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
jdbc_username=root
jdbc_password=lixun033
project_src =src/main/java
project_mapper_xml =src/main/resources/sqlmapper
#class_path=C:/Users/admin/.m2/repository/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.jar
class_path=D:/devTools/LocalRepository/mysql/mysql-connector-java/5.1.18/mysql-connector-java-5.1.18.jar
package com.enjoylearning.mybatis;
import java.io.IOException;
import java.io.InputStream;
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.Before;
import org.junit.Test;
import com.enjoylearning.mybatis.entity.TUser;
import com.enjoylearning.mybatis.mapper.TUserMapper;
public class MybatisQuickStart {
private SqlSessionFactory sqlSessionFactory;
@Before
public void init() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
// 1.读取mybatis配置文件创SqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
}
@Test
// 快速入门
public void quickStart() throws IOException {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
// 4.执行查询语句并返回结果
TUser user = mapper.selectByPrimaryKey(1);
System.out.println(user.toString());
}
}
5.一次访问数据库的过程
SqlSessionFactoryBuilder:读取配置信
息创建SqlSessionFactory,建造者模式,
方法级别生命周期;
SqlSessionFactory:创建Sqlsession,工
厂单例模式,存在于程序的整个生命周
期;
SqlSession:代表一次数据库连接,可
以直接发送SQL执行,也可以通过调用
Mapper访问数据库;线程不安全,要保
证线程独享(方法级);
SQL Mapper:由一个Java接口和XML文
件组成,包含了要执行的SQL语句和结果
集映射规则。方法级别生命周期;
6.mybatis核心配置文件:
<?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 resource="db.properties" />
<settings>
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!--配置environment环境 -->
<environments default="development">
<!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="UNPOOLED">
<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>
<!-- 映射文件,mapper的配置文件 -->
<!-- <mappers>
直接映射到相应的mapper文件
<mapper resource="sqlmapper/TUserMapper.xml" />
</mappers> -->
<mappers>
<mapper class="com.enjoylearning.mybatis.mapper.TUserMapper" />
</mappers>
</configuration>
7.Mybatis配置 environments
1) environment 元素是配置一个数据源的开始,属性id是它的唯一标识
2) transactionManager 元素配置数据库事务,其中type属性有三种配置方式
- jdbc,采用jdbc的方式管理事务;
- managed,采用容器的方式管理事务,在JNDI数据源中使用;
- 自定义,自定义数据库事务管理办法;
3) dataSource 元素配置数据源连接信息,type属性是连接数据库的方式配置,有四种配置方式 - UNPOOLED 非连接池方式连接
- POOLED 使用连接池连接
- JNDI 使用JNDI数据源
- 自定义数据源
<!--配置environment环境 -->
<environments default="development">
<!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="UNPOOLED">
<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>
databaseIdProvider配置:
MyBatis可以根据不同的数据库厂商执行不同的语句,用于一个系统
内多厂商数据源支持。也就是说,可以选择mysql,oracle,SqlServer。
8.Mybatis配置mappers
配置引入映射器的方法。可以使用相对于类路径的资源引用、或完全
限定资源定位符(包括file:///的URL),或类名和包名等等
<!-- 映射文件,mapper的配置文件 -->
<!-- <mappers>
直接映射到相应的mapper文件
<mapper resource="sqlmapper/TUserMapper.xml" />
</mappers> -->
<mappers>
<mapper class="com.enjoylearning.mybatis.mapper.TUserMapper" />
</mappers>
使用 第二种:类注册方式引用 与 第三种:使用包名引入引射器名,需要将接口类与对应的包含sql语句的xml文件放在同一个包下。
不推荐使用该方式。
第四种,强烈不推荐,使用全路径(某个盘里某个文件夹下)。
9.Mybatis配置 setting
设置,用于指定MyBatis的一些全局配置属性,这些属性非常重要,
它们会改变MyBatis的运行时行为;
所有mybatis核心配置模板:
<?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>
<!-- 这个配置使全局的映射器启用或禁用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载 -->
<setting name="aggressiveLazyLoading" value="true" />
<!-- 允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动) -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两种方法来决定所使用的驱动 -->
<setting name="useColumnLabel" value="true" />
<!-- 允许JDBC支持生成的键。需要适合的驱动。如果设置为true则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如Derby) -->
<setting name="useGeneratedKeys" value="true" />
<!-- 指定MyBatis如何自动映射列到字段/属性。PARTIAL只会自动映射简单,没有嵌套的结果。FULL会自动映射任意复杂的结果(嵌套的或其他情况) -->
<setting name="autoMappingBehavior" value="PARTIAL" />
<!--当检测出未知列(或未知属性)时,如何处理,默认情况下没有任何提示,这在测试的时候很不方便,不容易找到错误。 NONE : 不做任何处理
(默认值) WARNING : 警告日志形式的详细信息 FAILING : 映射失败,抛出异常和详细信息 -->
<setting name="autoMappingUnknownColumnBehavior" value="WARNING" />
<!-- 配置默认的执行器。SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理语句。BATCH执行器重用语句和批量更新 -->
<setting name="defaultExecutorType" value="SIMPLE" />
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
<setting name="defaultStatementTimeout" value="25000" />
<!--设置查询返回值数量,可以被查询数值覆盖 -->
<setting name="defaultFetchSize" value="100" />
<!-- 允许在嵌套语句中使用分页 -->
<setting name="safeRowBoundsEnabled" value="false" />
<!--是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn
的类似映射。 -->
<setting name="mapUnderscoreToCamelCase" value="false" />
<!--MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。
默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession
的不同调用将不会共享数据。 -->
<setting name="localCacheScope" value="SESSION" />
<!-- 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如
NULL、VARCHAR OTHER。 -->
<setting name="jdbcTypeForNull" value="OTHER" />
<!-- 指定哪个对象的方法触发一次延迟加载。 -->
<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString" />
</settings>
<!-- 别名定义 -->
<typeAliases>
<typeAlias alias="pageAccessURL" type="com.lgm.mybatis.model.PageAccessURL" />
</typeAliases>
<!--自定义类型处理器 -->
<typeHandlers>
<!-- <typeHandler handler="com.xhm.util.BooleanTypeHandlder" /> -->
<!--扫描整个包下的自定义类型处理器 -->
<package name="com.xhm.util" />
</typeHandlers>
<!--plugins插件之 分页拦截器 -->
<plugins>
<plugin interceptor="com.xhm.util.PageInterceptor"></plugin>
</plugins>
<!--配置environment环境 -->
<environments default="development">
<!-- 环境配置1,每个SqlSessionFactory对应一个环境 -->
<environment id="development1">
<!-- 事务配置 type= JDBC、MANAGED 1.JDBC:这个配置直接简单使用了JDBC的提交和回滚设置。它依赖于从数据源得到的连接来管理事务范围。
2.MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接。而它会让容器来管理事务的整个生命周期(比如Spring或JEE应用服务器的上下文)。
默认情况下它会关闭连接。然而一些容器并不希望这样,因此如果你需要从连接中停止它,将closeConnection属性设置为false -->
<transactionManager type="JDBC" />
<!-- <transactionManager type="MANAGED"> <property name="closeConnection"
value="false"/> </transactionManager> -->
<!-- 数据源类型:type = UNPOOLED、POOLED、JNDI 1.UNPOOLED:这个数据源的实现是每次被请求时简单打开和关闭连接。它有一点慢,这是对简单应用程序的一个很好的选择,因为它不需要及时的可用连接。
不同的数据库对这个的表现也是不一样的,所以对某些数据库来说配置数据源并不重要,这个配置也是闲置的 2.POOLED:这是JDBC连接对象的数据源连接池的实现,用来避免创建新的连接实例时必要的初始连接和认证时间。
这是一种当前Web应用程序用来快速响应请求很流行的方法。 3.JNDI:这个数据源的实现是为了使用如Spring或应用服务器这类的容器,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用 -->
<dataSource type="UNPOOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xhm" />
<property name="username" value="root" />
<property name="password" value="root" />
<!-- 默认连接事务隔离级别 <property name="defaultTransactionIsolationLevel" value=""
/> -->
</dataSource>
</environment>
<!-- 环境配置2 -->
<environment id="development2">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/xhm" />
<property name="username" value="root" />
<property name="password" value="root" />
<!-- 在任意时间存在的活动(也就是正在使用)连接的数量 -->
<property name="poolMaximumActiveConnections" value="10" />
<!-- 任意时间存在的空闲连接数 -->
<property name="poolMaximumIdleConnections" value="5" />
<!-- 在被强制返回之前,池中连接被检查的时间 -->
<property name="poolMaximumCheckoutTime" value="20000" />
<!-- 这是给连接池一个打印日志状态机会的低层次设置,还有重新尝试获得连接,这些情况下往往需要很长时间(为了避免连接池没有配置时静默失败) -->
<property name="poolTimeToWait" value="20000" />
<!-- 发送到数据的侦测查询,用来验证连接是否正常工作,并且准备接受请求。 -->
<property name="poolPingQuery" value="NO PING QUERY SET" />
<!-- 这是开启或禁用侦测查询。如果开启,你必须用一个合法的SQL语句(最好是很快速的)设置poolPingQuery属性 -->
<property name="poolPingEnabled" value="false" />
<!-- 这是用来配置poolPingQuery多次时间被用一次。这可以被设置匹配标准的数据库连接超时时间,来避免不必要的侦测 -->
<property name="poolPingConnectionsNotUsedFor" value="0" />
</dataSource>
</environment>
<!-- 环境配置3 -->
<environment id="development3">
<transactionManager type="JDBC" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jndi/mybatis" />
<property name="env.encoding" value="UTF8" />
<!-- <property name="initial_context" value=""/> <property name="env.encoding"
value="UTF8"/> -->
</dataSource>
</environment>
</environments>
<!-- 映射文件,mapper的配置文件 -->
<mappers>
<!--直接映射到相应的mapper文件 -->
<mapper resource="com/xhm/mapper/UserMapper.xml" />
<!--扫描包路径下所有xxMapper.xml文件 -->
<package name="com.xhm.mapper" />
</mappers>
</configuration>
cacheEnabled:开启与关闭的是二级缓存,对一级缓存无效。
localCacheScope:对于一级缓存的配置,SESSION表示使用一级缓存, STATEMENT不使用。
logImpl:指定 MyBatis 所用日志的具体实现,未指定时将自动查找。默认使用JDK_LOGGING。
10.基于xml配置的映射器
基于接口,所编写的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.enjoylearning.mybatis.mapper.TUserMapper">
<select id="selectByPrimaryKey" resultType="com.enjoylearning.mybatis.entity.TUser" parameterType="java.lang.Integer">
select
id,
user_name ,
real_name ,
sex,
mobile,
email,
note,
position_id positionId
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
</mapper>
cache – 给定命名空间的缓存配置。
cache-ref – 其他命名空间缓存配置的引用。
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
sql – 可被其他语句引用的可重用语句块。
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
sql:提高sql复用率。如
<sql id="Base_Column_List">
id, user_name, real_name, sex, mobile, email, note,
position_id
</sql>
1)select元素
resultMap与resultType只能使用一个。
如:
<?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.enjoylearning.mybatis.mapper.TUserMapper">
<resultMap id="BaseResultMap" type="TUser">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
<resultMap id="userAndJobs1" extends="BaseResultMap" type="TUser">
<collection property="jobs"
ofType="com.enjoylearning.mybatis.entity.TJobHistory">
<result column="comp_name" property="compName" jdbcType="VARCHAR" />
<result column="years" property="years" jdbcType="INTEGER" />
<result column="title" property="title" jdbcType="VARCHAR" />
</collection>
</resultMap>
<resultMap id="userAndJobs2" extends="BaseResultMap" type="TUser">
<collection property="jobs" fetchType="lazy" column="id"
select="com.enjoylearning.mybatis.mapper.TJobHistoryMapper.selectByUserId" />
</resultMap>
<select id="selectUserJobs1" resultMap="userAndJobs1">
select
a.id,
a.user_name,
a.real_name,
a.sex,
a.mobile,
b.comp_name,
b.years,
b.title
from t_user a,
t_job_history b
where a.id = b.user_id
</select>
<select id="selectUserJobs2" resultMap="userAndJobs2">
select
a.id,
a.user_name,
a.real_name,
a.sex,
a.mobile
from t_user a
</select>
<select id="selectByEmailAndSex1" resultMap="BaseResultMap"
parameterType="map">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex2" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectByEmailAndSex3" resultMap="BaseResultMap"
parameterType="com.enjoylearning.mybatis.entity.EmailSexBean">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
<select id="selectBySymbol" resultMap="BaseResultMap">
select
#{inCol}
from ${tableName} a
where a.sex = #{sex}
order by ${orderStr}
</select>
<select id="selectIfOper" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
where
<if test="email != null and email != ''">
a.email like CONCAT('%', #{email}, '%') and
</if>
<if test="sex != null ">
a.sex = #{sex}
</if>
</select>
<select id="selectIfandWhereOper" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
<where>
<if test="email != null and email != ''">
and a.email like CONCAT('%', #{email}, '%')
</if>
<if test="sex != null ">
and a.sex = #{sex}
</if>
</where>
</select>
<update id="updateIfOper" parameterType="TUser">
update t_user
set
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="realName != null">
real_name = #{realName,jdbcType=VARCHAR},
</if>
<if test="sex != null">
sex = #{sex,jdbcType=TINYINT},
</if>
<if test="mobile != null">
mobile = #{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
email = #{email,jdbcType=VARCHAR},
</if>
<if test="note != null">
note = #{note,jdbcType=VARCHAR},
</if>
<if test="positionId != null">
position_id = #{positionId,jdbcType=INTEGER}
</if>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateIfAndSetOper" parameterType="TUser">
update t_user
<set>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="realName != null">
real_name = #{realName,jdbcType=VARCHAR},
</if>
<if test="sex != null">
sex = #{sex,jdbcType=TINYINT},
</if>
<if test="mobile != null">
mobile = #{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
email = #{email,jdbcType=VARCHAR},
</if>
<if test="note != null">
note = #{note,jdbcType=VARCHAR},
</if>
<if test="positionId != null">
position_id = #{positionId,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<insert id="insertIfOper" parameterType="TUser">
insert into t_user (
<if test="id != null">
id,
</if>
<if test="userName != null">
user_name,
</if>
<if test="realName != null">
real_name,
</if>
<if test="sex != null">
sex,
</if>
<if test="mobile != null">
mobile,
</if>
<if test="email != null">
email,
</if>
<if test="note != null">
note,
</if>
<if test="positionId != null">
position_id
</if>
)
values(
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="realName != null">
#{realName,jdbcType=VARCHAR},
</if>
<if test="sex != null">
#{sex,jdbcType=TINYINT},
</if>
<if test="mobile != null">
#{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
#{email,jdbcType=VARCHAR},
</if>
<if test="note != null">
#{note,jdbcType=VARCHAR},
</if>
<if test="positionId != null">
#{positionId,jdbcType=INTEGER}
</if>
)
</insert>
<select id="selectForeach4In" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
where a.user_name in
<foreach collection="array" open="(" close=")" item="userName" index="i" separator=",">
#{userName}
</foreach>
</select>
<insert id="insertForeach4Batch">
insert into t_user (user_name, real_name,
sex, mobile,email,note, position_id)
values
<foreach collection="list" separator="," item="user">
(
#{user.userName,jdbcType=VARCHAR},
#{user.realName,jdbcType=VARCHAR},
#{user.sex,jdbcType=TINYINT},
#{user.mobile,jdbcType=VARCHAR},
#{user.email,jdbcType=VARCHAR},
#{user.note,jdbcType=VARCHAR},
#{user.positionId,jdbcType=INTEGER}
)
</foreach>
</insert>
<sql id="Base_Column_List">
id, user_name, real_name, sex, mobile, email, note,
position_id
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer">
select
<include refid="Base_Column_List" />
from t_user
where id = #{id,jdbcType=INTEGER}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
delete from t_user
where id = #{id,jdbcType=INTEGER}
</delete>
<insert id="insert1" parameterType="TUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
<insert id="insert2" parameterType="TUser">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
<insert id="insertSelective" parameterType="TUser">
insert into t_user
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="userName != null">
user_name,
</if>
<if test="realName != null">
real_name,
</if>
<if test="sex != null">
sex,
</if>
<if test="mobile != null">
mobile,
</if>
<if test="email != null">
email,
</if>
<if test="note != null">
note,
</if>
<if test="positionId != null">
position_id,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id,jdbcType=INTEGER},
</if>
<if test="userName != null">
#{userName,jdbcType=VARCHAR},
</if>
<if test="realName != null">
#{realName,jdbcType=VARCHAR},
</if>
<if test="sex != null">
#{sex,jdbcType=TINYINT},
</if>
<if test="mobile != null">
#{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
#{email,jdbcType=VARCHAR},
</if>
<if test="note != null">
#{note,jdbcType=VARCHAR},
</if>
<if test="positionId != null">
#{positionId,jdbcType=INTEGER},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="TUser">
update t_user
<set>
<if test="userName != null">
user_name = #{userName,jdbcType=VARCHAR},
</if>
<if test="realName != null">
real_name = #{realName,jdbcType=VARCHAR},
</if>
<if test="sex != null">
sex = #{sex,jdbcType=TINYINT},
</if>
<if test="mobile != null">
mobile = #{mobile,jdbcType=VARCHAR},
</if>
<if test="email != null">
email = #{email,jdbcType=VARCHAR},
</if>
<if test="note != null">
note = #{note,jdbcType=VARCHAR},
</if>
<if test="positionId != null">
position_id = #{positionId,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
<update id="updateByPrimaryKey" parameterType="TUser">
update t_user
set
user_name = #{userName,jdbcType=VARCHAR},
real_name =
#{realName,jdbcType=VARCHAR},
sex = #{sex,jdbcType=TINYINT},
mobile =
#{mobile,jdbcType=VARCHAR},
email = #{email,jdbcType=VARCHAR},
note =
#{note,jdbcType=VARCHAR},
position_id = #{positionId,jdbcType=INTEGER}
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
当接口中,方法入参有多个时:
1)使用map传参:
List<TUser> selectByEmailAndSex1(Map<String, Object> param);
<select id="selectByEmailAndSex1" resultMap="BaseResultMap"
parameterType="map">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
方法二:使用@Param注解传入
List<TUser> selectByEmailAndSex2(@Param("email")String email,@Param("sex")Byte sex);
<select id="selectByEmailAndSex2" resultMap="BaseResultMap">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
方法三:将参数封装一个bean(当单个参数超过5个时)
List<TUser> selectByEmailAndSex3(EmailSexBean esb);
<select id="selectByEmailAndSex3" resultMap="BaseResultMap"
parameterType="com.enjoylearning.mybatis.entity.EmailSexBean">
select
<include refid="Base_Column_List" />
from t_user a
where a.email like CONCAT('%', #{email}, '%') and
a.sex = #{sex}
</select>
// 多参数查询
@Test
public void testManyParamQuery() {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
String email = "qq.com";
Byte sex = 1;
// 第一种方式使用map
Map<String, Object> params = new HashMap<String, Object>();
params.put("email", email);
params.put("sex", sex);
List<TUser> list1 = mapper.selectByEmailAndSex1(params);
System.out.println(list1.size());
// 第二种方式直接使用参数
List<TUser> list2 = mapper.selectByEmailAndSex2(email, sex);
System.out.println(list2.size());
// 第三种方式用对象
EmailSexBean esb = new EmailSexBean();
esb.setEmail(email);
esb.setSex(sex);
List<TUser> list3 = mapper.selectByEmailAndSex3(esb);
System.out.println(list3.size());
}
杜绝使用map原因:
主要是因为,代码不易维护,其他人读该代码时,需要仔细查看map中有哪些属性?可读性差。
11.自动映射与手动映射:
优先推荐使用手动映射,因为可以将java代码与表结构解耦,如果将来修改表时,只需要一些配置文件就可以了。
12.resultMap元素 子元素
id作用:1.唯一标识一条数据;2.查询时,数据根据id合并。
<resultMap id="BaseResultMap" type="TUser">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
1)id & result
id 和 result 都将一个列的值映射到一个简单数据类型(字符串,整型,双精度浮点数,日期等)的属性或字段
两者之间的唯一不同是, id 表示的结果将是对象的标识属性,这会在比较对象实例时用到。 这样可以提高整体的性能,尤其是缓存和嵌套结果映射(也就是联合映射)的时候
如果是自定义的类型转换(java对象属性与数据源中字段转换),如枚举,需要自定义转换规则:
typeHandler
2)constructor用法:
<resultMap id="BaseResultMap" type="TUser">
<!-- <constructor>
<idArg column="id" javaType="int"/>
<arg column="user_name" javaType="String"/>
</constructor> -->
<id column="id" property="id" jdbcType="INTEGER" />
<result column="user_name" property="userName" jdbcType="VARCHAR" />
<result column="real_name" property="realName" jdbcType="VARCHAR" />
<result column="sex" property="sex" jdbcType="TINYINT" />
<result column="mobile" property="mobile" jdbcType="VARCHAR" />
<result column="email" property="email" jdbcType="VARCHAR" />
<result column="note" property="note" jdbcType="VARCHAR" />
<result column="position_id" property="positionId" jdbcType="INTEGER" />
</resultMap>
如上配置中,使用constructor标签时:
package com.enjoylearning.mybatis.entity;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public class TUser {
private Integer id;
private String userName;
private String realName;
private Byte sex;
private String mobile;
private String email;
private String note;
private Integer positionId;
private List<TJobHistory> jobs ;
/*
public TUser(Integer id, String userName) {
super();
this.id = id;
this.userName = userName;
}
*/
.......
类中存在构造方法时。
constructor使用场景:如:.没有无参构造方法。(如果没有get,set方法时,也可以反射赋值成功,springmvc传参时,调用的是set方法,不要混淆)。
为什么互联网项目不使用多表联合查询,尽量使用单表查询?
因为,如果数据量过大,分库分表后,多表查询可能会报错。
13.insert, update 和 delete
int insert1(TUser record);
<insert id="insert1" parameterType="TUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
useGeneratedKeys:主键生成策略
keyProperty:指定id。
测试:
@Test
// 测试插入数据自动生成id
public void testInsertGenerateId1() throws IOException {
// 2.获取sqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应mapper
TUserMapper mapper = sqlSession.getMapper(TUserMapper.class);
// 4.执行查询语句并返回结果
TUser user1 = new TUser();
user1.setUserName("test1");
user1.setRealName("realname1");
user1.setEmail("myemail1");
mapper.insert1(user1);
sqlSession.commit();
System.out.println(user1.getId());
}
<insert id="insert1" parameterType="TUser" useGeneratedKeys="true" keyProperty="id">
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
如果去除useGeneratedKeys,keyProperty属性,则该测试代码返回值为null,如果配置,则可以拿到。
如果配置useGeneratedKeys,keyProperty属性后,如果传入的待持久化的对象中,存在自定义id值,则会持久化自定义值,如果传入的id为null,则数据库会根据主键生成规则,自动生成id值。
这两个属性,只能使用在mysql与SqlServer中,oracle不支持自增。
14.selectKey元素
selectKey:
int insert2(TUser record);
<insert id="insert2" parameterType="TUser">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
insert into t_user (id, user_name, real_name,
sex, mobile,
email,
note, position_id)
values (#{id,jdbcType=INTEGER},
#{userName,jdbcType=VARCHAR},
#{realName,jdbcType=VARCHAR},
#{sex,jdbcType=TINYINT}, #{mobile,jdbcType=VARCHAR},
#{email,jdbcType=VARCHAR},
#{note,jdbcType=VARCHAR},
#{positionId,jdbcType=INTEGER})
</insert>
其中,select LAST_INSERT_ID()表示得到数据库中最新的字段,插入