A. mybatis中字段名与实体属性名不一样的情况下插入数据的方法,在xml配置文件里sql语句应该怎么写
查询语句是 MyBatis 中最常用的元素之一,本文涉及mybatis的单表查询操作,关联表有关的查询会后续补充。
巧妇难为无米之炊,要想从数据库中表中取出数据并转化为javaBean,所以,我们要先准备javabean以及与其对应的数据表。
javaBean:
public class President {
private int id;
private String name;
@Override
public String toString() {
return "President [id=" + id + ", name=" + name + "]";
}
//get set 方法.....
}
创建两个对应的数据库表,并插入两条数据:
create table president1(
p_id int not null auto_increment primary key,
p_name varchar(50) not null
);
insert into president1(p_name) values('lily'),('Tom');
create table president2(
id int not null auto_increment primary key,
name varchar(50) not null
);
insert into president2(name) values('lily'),('Tom');
创建两个数据库是为了测试两个不同的查询状况,
数据库字段名与实体类属性名相同
从sql表可以看出president2的字段名与javabean:President的属性名完全相同,这种情况下mybatis的select操作非常简单:
<!-- 从表 president2中查询-->
<select id="getPreByIdPresident2" parameterType="int" resultType="President">
select * from president2 where id=#{id}
</select>
此时mybatis运用反射机制会将查询返回的结果(id,name)封装成President对象。
如果从表president1中查询,同样采用上面的sql语句
<!-- 从表 president1中查询-->
<select id="getPreByIdPresident1" parameterType="int" resultType="President">
<span style="white-space:pre"> </span>President p1 = session.selectOne(statement+"getPreByIdPresident1", 1);
<span style="white-space:pre"> </span>System.out.println("表president1中查询"+p1);
</select>
此时如果用getPreByIdPresident1进行查询,返回的结果会是null,我们将上面的sql语句在mysql中执行下:
有结果返回,但是返回的字段名为(p_id,p_name)这种结果mybatis在解析时无法与President类对应。多数情况下实体类属性名与数据库表的字段名都会有差异,这种情况如果mybatis不能处理也就太low了。
数据库字段名与实体类属性名不相同
mybatis针对该种情况有两种解决方法,但是归根到底都是同一种实现。
Method1:定义一个ResultMap将数据库字段名与实体类属性名做个映射
我们欲从表president1中查询数据,此时的mapper配置如下:
<resultMap type="President" id="getFromPresident2">
<!-- 主键必须用id标签映射,其他的用非集合用result映射 集合类用collection映射 -->
<!-- column为数据库字段名,property为实体类属性名 -->
<id column="p_id" property="id" />
<result column="p_name" property="name" />
</resultMap>
<select id="getPreByIdPresident1Method1" resultMap="getFromPresident2">
select * from president1 where p_id=#{id}
</select>
首先定义了一个resultMap,将数据库表的字段名与实体类属性名做了一一对应,其中type为实体类(此处运用的类别名),id为了在select标签中引用映射结果。
在select标签中并没有用resultType属性,而使用了resultMap,即为上面定义的resultMap,mybatis会根据resultMap中的映射关系去构造President
Method1:直接在sql语句中使用别名
<!-- 从表 president1中查询 -->
<select id="getPreByIdPresident1Method2" resultType="President">
select p_id id,p_name name from president1 where p_id=#{id}
</select>
这种方法会查到实际的数据,这种方法与字段名和属性名相同都是基于相同的原理:MyBatis 会在幕后自动创建一个 ResultMap,基于属性名来映射列到JavaBean 的属性上。即mybatis底层都是通过创建ResultMap来进行关系的映射,与method1原理相同。。
B. spring整合mybatis怎样配置注解
mybatis和spring的整合步骤:
1)使用mybatis,必须有个全局配置文件configuration.xml,来配置mybatis的缓存,延迟加载等等一系列属性,该配置文件示例如下:
Java代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<configuration>
<settings>
<!-- 全局映射器启用缓存 -->
<setting name="cacheEnabled" value="true" />
<!-- 查询时,关闭关联对象即时加载以提高性能 -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 设置关联对象加载的形态,此处为按需加载字段(加载字段由SQL指 定),不会加载关联表的所有字段,以提高性能 -->
<setting name="aggressiveLazyLoading" value="false" />
<!-- 对于未知的SQL查询,允许返回不同的结果集以达到通用的效果 -->
<setting name="multipleResultSetsEnabled" value="true" />
<!-- 允许使用列标签代替列名 -->
<setting name="useColumnLabel" value="true" />
<!-- 允许使用自定义的主键值(比如由程序生成的UUID 32位编码作为键值),数据表的PK生成策略将被覆盖 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 给予被嵌套的resultMap以字段-属性的映射支持 -->
<setting name="autoMappingBehavior" value="FULL" />
<!-- 对于批量更新操作缓存SQL以提高性能 -->
<setting name="defaultExecutorType" value="BATCH" />
<!-- 数据库超过25000秒仍未响应则超时 -->
<setting name="defaultStatementTimeout" value="25000" />
</settings>
<!-- 全局别名设置,在映射文件中只需写别名,而不必写出整个类路径 -->
<typeAliases>
<typeAlias alias="TestBean"
type="com.wotao.taotao.persist.test.dataobject.TestBean" />
</typeAliases>
<!-- 非注解的sql映射文件配置,如果使用mybatis注解,该mapper无需配置,但是如果mybatis注解中包含@resultMap注解,则mapper必须配置,给resultMap注解使用 -->
<mappers>
<mapper resource="persist/test/orm/test.xml" />
</mappers>
</configuration>
2)该文件放在资源文件的任意classpath目录下,假设这里就直接放在资源根目录,等会spring需要引用该文件。
查看ibatis-3-config.dtd发现除了settings和typeAliases还有其他众多元素,比如properties,objectFactory,environments等等,这些元素基本上都包含着一些环境配置,数据源定义,数据库事务等等,在单独使用mybatis的时候非常重要,比如通过以构造参数的形式去实例化一个sqlsessionFactory,就像这样:
Java代码
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, properties);
SqlSessionFactory factory = sqlSessionFactoryBuilder.build(reader, environment, properties);
而typeHandlers则用来自定义映射规则,如可以自定义将Character映射为varchar,plugins元素则放了一些拦截器接口。
2)在spring配置文件中指定c3p0数据源定义如下:
Java代码
<!-- c3p0 connection pool configuration -->
<bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<!-- 数据库驱动 -->
<property name="driverClass" value="${db.driver.class}" />
<!-- 连接URL串 -->
<property name="jdbcUrl" value="${db.url}" />
<!-- 连接用户名 -->
<property name="user" value="${db.username}" />
<!-- 连接密码 -->
<property name="password" value="${db.password}" />
<!-- 初始化连接池时连接数量为5个 -->
<property name="initialPoolSize" value="5" />
<!-- 允许最小连接数量为5个 -->
<property name="minPoolSize" value="5" />
<!-- 允许最大连接数量为20个 -->
<property name="maxPoolSize" value="20" />
<!-- 允许连接池最大生成100个PreparedStatement对象 -->
<property name="maxStatements" value="100" />
<!-- 连接有效时间,连接超过3600秒未使用,则该连接丢弃 -->
<property name="maxIdleTime" value="3600" />
<!-- 连接用完时,一次产生的新连接步进值为2 -->
<property name="acquireIncrement" value="2" />
<!-- 获取连接失败后再尝试10次,再失败则返回DAOException异常 -->
<property name="acquireRetryAttempts" value="10" />
<!-- 获取下一次连接时最短间隔600毫秒,有助于提高性能 -->
<property name="acquireRetryDelay" value="600" />
<!-- 检查连接的有效性,此处小弟不是很懂什么意思 -->
<property name="testConnectionOnCheckin" value="true" />
<!-- 每个1200秒检查连接对象状态 -->
<property name="idleConnectionTestPeriod" value="1200" />
<!-- 获取新连接的超时时间为10000毫秒 -->
<property name="checkoutTimeout" value="10000" />
</bean>
配置中的${}都是占位符,在指定数据库驱动打war时会自动替换,替换的值在父pom中配置。
3)需要一个sessionFactory来生成session,sessionFactory配置如下:
Java代码
<bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:configuration.xml" />
<property name="dataSource" ref="testDataSource" />
</bean>
4)配置一个映射器接口来对应sqlSessionTemplate,该映射器接口定义了接口方法:
Java代码
<!-- data OR mapping interface -->
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="testSqlSessionFactory" />
<property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" />
</bean>
5)至此,一个完整的myabtis整合spring的配置文件看起来应该如下所示:
Java代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- c3p0 connection pool configuration -->
<bean id="testDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${db.driver.class}" />
<property name="jdbcUrl" value="${db.url}" />
<property name="user" value="${db.username}" />
<property name="password" value="${db.password}" />
<property name="initialPoolSize" value="5" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="20" />
<property name="maxStatements" value="100" />
<property name="maxIdleTime" value="3600" />
<property name="acquireIncrement" value="2" />
<property name="acquireRetryAttempts" value="10" />
<property name="acquireRetryDelay" value="600" />
<property name="testConnectionOnCheckin" value="true" />
<property name="idleConnectionTestPeriod" value="1200" />
<property name="checkoutTimeout" value="10000" />
</bean>
<bean id="testSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="configLocation" value="classpath:configuration.xml" />
<property name="dataSource" ref="testDataSource" />
</bean>
<!-- data OR mapping interface -->
<bean id="testMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="testSqlSessionFactory" />
<property name="mapperInterface" value="com.wotao.taotao.persist.test.mapper.TestMapper" />
</bean>
<!-- add your own Mapper here -->
<!-- comment here, using annotation -->
<!-- <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate"> -->
<!-- <constructor-arg index="0" ref="sqlSessionFactory" /> -->
<!-- </bean> -->
<!-- base DAO class, for mole business, extend this class in DAO -->
<!-- <bean id="testBaseDAO" class="com.test..TestBaseDAO"> -->
<!-- <property name="sqlSessionTemplate" ref="sqlSessionTemplate" /> -->
<!-- </bean> -->
<!-- <bean id="testDAO" class="com.test..impl.TestDAOImpl" /> -->
<!-- you can DI Bean if you don't like use annotation -->
</beans>
C. mybatis中写sql语句用注解好还是xml文档
您好,在spring中配置
<!-- 通过扫描的模式,扫描目录在com.mrorder.目录下,所有的mapper都继承SqlMapper接口的接口 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.mrorder."/>
<property name="markerInterface" value="com.mrorder..SqlMapper"/>
</bean>
自己写层方法的接口
public interface OrderMapper extends SqlMapper{
@Select("select * from tbl_order where room like #{room} and mydate like #{mydate}")
public List<Order> getbyroom(OrderPara op);
}
这样整个语句是写死的,必须有2个参数,在这种模式下,如何能实现根据room和mydate是否为空来动态的拼写sql语句
比如当mydate=""
Select("select * from tbl_order where room like #{room} ")
public List<Order> getbyroom(OrderPara op);
如果用xml来配置语句的话,可以用<when test="title != null">
and mydate= #{mydate}
</when>
如果是用@Select 这种 改如何做呢?
利用自定义注解,通过反射,拼出SQL语句。
D. 使用mybatis 执行sql删除数据的存储过程xml里应该怎么写
Java mysql mybatis批量更新数据库,采用以下写法即可执行,但是数据库连接必须配置:&allowMultiQueries=true
例如:jdbc:mysql://192.168.1.236:3306/test?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
<update id="batchUpdate" parameterType="java.util.List">
<foreach collection="list" item="item" index="index" open="" close="" separator=";">
update test
<set>
test=${item.test}+1
</set>
where id = ${item.id}
</foreach>
</update>
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录.
E. Mybatis 教程之Mybatis注解开发
mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到了 MyBatis 3提供了新的基于注解的配置。
这里讲述 注解开发方式:
首先我们需要获取 SqlSession :
参数设置为 true 表示开启自动提交模式。
session 在注解形式的使用方式如:
所以mybatis 的使用使用三部分:
这里主要讲解 Mapper 层的开发规则。
sql 类型主要分成 : select @Select(${sql}) , update @Update(${sql}) , insert @Insert($sql) , delete (${sql}) .
@Results 用来设置table信息与bean相关字段的映射关系, 每一个字段的关系使用 @Result 控制。
默认情况下对于每一table字段,例如 name , 会调用 bean 中的 setName(..) . 如果找不到,对于新版本的 mybatis 会报错。
例如上面的 cluster_name 会调用 setCluster_name() . 但是java 中使用的 clusterName ,可以通过 Result 注解控制.
@ResultMap 可以通过Id,应用其他的 Results
还有一种更改映射的方式:
mapUnderscoreToCamelCase 设置为true, 之后会自动实现 mysql 中的unix命名方式转为java的驼峰表示法。
@MapKey 此注解应用将查询数据转为 Map<>, 注意的是MapKey()中的id最终调用bean的getId 获取数据,所以需要映射bean字段而不是table.
@Param注解用于给方法参数起一个名字。以下是笔者总结的使用原则:
在方法只接受一个参数的情况下,可以不使用@Param。
在方法接受多个参数的情况下,建议一定要使用@Param注解给参数命名。
insert 时获取自增主键的方式:
法一:
法二:
#{} 的作用主要是替换预编译语句(PrepareStatement)中的占位符 ? :
对于 : INSERT INTO user (name) VALUES (#{name}); ==> INSERT INTO user (name) VALUES (?);
${} 符号的作用是直接进行字符串替换:
对于 : INSERT INTO user (name) VALUES ('${name}'); ==> INSERT INTO user (name) VALUES ('tiansho');
F. mybatis生成的sql怎么使用
因为配置文件提供了 mybatis-generator所需要的参数信息:
* 其中classPathEntry 是引用的jdbc的类路径,这里将jdbc jar和generator的jar包放在一起了;
* commentGenerator 是用来除去时间信息的,这在配合类似subversion的代码管理工具时使用很有效,因为可以减少没有必要的注释迁入;
* jdbcConnection是指定的jdbc的连接信息;
* javaTypeResolver式类型转换的信息,这里并没有用到;
* javaModelGenerator是模型的生成信息,这里将指定这些Java model类的生成路径;
* sqlMapGenerator是mybatis 的sqlMapper XML文件的生成信息,包括生成路径等;
* javaClientGenerator是应用接口的生成信息;
* table是用户指定的被生成相关信息的表,它必须在指定的jdbc连接中已经被建立。
G. 如何MyBatis中使用动态SQL查询与注释
首先,楼主需了解何为动态sql,何为静态sql,这是他们的区别:
静态 SQL:静态 SQL 语句一般用于嵌入式 SQL 应用中,在程序运行前,SQL 语句必须是确定的,例如 SQL 语句中涉及的列名和表名必须是存在的。静态 SQL 语句的编译是在应用程序运行前进行的,编译的结果会存储在数据库内部。而后程序运行时,数据库将直接执行编译好的 SQL 语句,降低运行时的开销。静态SQL在编译时已经确定了引用的表和列。 宿主变量不改变表和列信息。 可以使用主变量改变查询参数值, 但是不能用主变量代替表名或列名。
动态 SQL:动态 SQL 语句是在应用程序运行时被编译和执行的,不在编译时确定 SQL 的表和列,而是让程序在运行时提供,并将SQL 语句文本传给 DBMS 执行。 静态 SQL 语句在编译时已经生成执行计划。 而动态 SQL 语句,只有在执行时才产生执行计划。动态 SQL 语句首先执行 PREPARE 语句要求 DBMS 分析、确认和优化语句,并为其生成执行计划。例如,使用 DB2 的交互式工具 CLP 访问数据库时,用户输入的 SQL 语句是不确定的,因此 SQL 语句只能被动态地编译。动态 SQL 的应用较多,常见的 CLI 和 JDBC 应用程序都使用动态 SQL。
下面是一个典型的在MyBatis中使用动态SQL:
<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User"> UPDATE users <trim prefix="SET" prefixOverrides=","> <if test="name != null and name != ''"> name = #{name} </if> <if test="age != null and age != ''"> , age = #{age} </if> <if test="birthday != null and birthday != ''"> , birthday = #{birthday} </if> </trim> where id = ${id}</update>
H. mybatis中xml映射和方法注解两种配置sql语句的方式是否可以同时存在
不能进行同时设置。执行会找不到接口的mapper代理工厂。mybatis会先解析xml文件,将解析后的sql封装在mapperstament中并放进Configuration的mappedStatements中,将命名空间和方法名(也就是id)作为key,mappedStatements是个自定义map。然后生成接口的代理工程,生产代理工厂后会解析注解,解析完注解,也会生成mapperstament,也会往统一的Configuration大对象里面放,但是放的时候自定义map会先判断是否存在,此时已经存在了,存在就会抛出IllegalArgumentException(name + " already contains value for " + key)。但是创建代理工厂的时候把异常吃掉了,所以加载的时候不会报错,但是不会给接口生成代理工厂。没有代理工厂,接口就没有实现类去操作。
I. 用mybatis开发sql怎么写
用Spring框架,在applicationContext.xml文件里配置以下内容:
<!-- 读取db.properties文件的内容 -->
<util:properties id = "jdbc" location = "classpath:db.properties"/>
<!-- 配置DataSource -->
<bean id = "ds" class = "org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value = "#{jdbc.driver}"/>
<property name="url" value = "#{jdbc.url}"/>
<property name="username" value = "#{jdbc.user}"/>
<property name="password" value = "#{jdbc.pwd}"/>
</bean>
<!-- 配置SqlSessionFactoryBean -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入DataSource -->
<property name="dataSource" ref="ds"/>
<!-- 注入映射文件的位置信息 -->
<property name="mapperLocations" value="classpath:com/tarena/oss/entity/*.xml"/>
</bean>
<!--
配置MapperSourceConfigurer:
扫描制定包下面所有的类,
创建符合Mapp接口要求的对象,
并且会将创建好的对象放到spring容器里面
-->
<bean class = "org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 注入要扫描的包名 -->
<property name="basePackage" value = "com.tarena.oss."/>
</bean>
其中,要导入的包有:
mybatis-3.2.5.jar
mybatis-spring-1.2.2.jar
写好实体类之后,在创建一个mapper.xml文件。
注:实体类的属性名一定要和表的字段名一致。在mapper.xml映射文件里写sql语句。格式为:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//ibatis.apache.org//DTD Mapper 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-mapper.dtd">
<mapper namespace="的路径名">
<!--
查询。
parameterType:如果返回值是一个整数,标准用法是java.lang.Integer,
可以简写为"int"。
-->
<select id = "和里面的方法名一致" parameterType="参数类型"
resultType="com.tarena.oss.entity.Admin">
查询的sql语句
</select>
<!--
使用resultMap来解决实体类的属性名,与表的字段名不一致的情况。
type属性: 实体类的名字。
property属性: 实体类的属性名。
column属性: 表的字段名。
注:如果属性名与字段名一样,就不用写了。
-->
</mapper>
其他语句在<mapper></mapper>里写,方法和select一样。
希望可以帮到你!
J. 如何解析Mybatis xml文件中配置的sql
首先抽象一个SQL语句类:
[java] view plain
public abstract class AbstractSQLStatementNode implements ISQLStatement {
protected List<ISQLStatement> sqlStatements = new ArrayList<>();
@Override
public void appendSQL(ISQLStatement sql) {
sqlStatements.add(sql);
}
@Override
public String getSQL(Object object) {
StringBuilder sb = new StringBuilder();
for (ISQLStatement stmt : sqlStatements) {
sb.append(stmt.getSQL(object));
}
return sb.toString().trim();
}
}
然后是文本SQL:
[java] view plain
public class PlainSQLNode extends AbstractSQLStatementNode {
private final String sql;
public PlainSQLNode(String sql) {
this.sql = sql;
}
@Override
public String getSQL(Object object) {
return sql;
}
@Override
public String toString() {
return sql;
}
}
以Mybatis xml中<if test="...">...</if>为例
[java] view plain
public class IfSQLNode extends AbstractSQLStatementNode {
private final String test;
public IfSQLNode(String test) {
this.test = test;
}
public String getTest() {
return test;
}
@Override
public String getSQL(Object object) {
try {
Boolean b = (Boolean) Ognl.getValue(test, object, Boolean.TYPE);
return b ? super.getSQL(object) : "";
}
catch (OgnlException e) {
throw new SQLSyntaxException(e);
}
}
}
再增加一个Include标签例
[java] view plain
public class IncludeSQLNode extends AbstractSQLStatementNode {
private final TableNode node;
private final String refid;
public IncludeSQLNode(TableNode node, String refid) {
this.node = node;
this.refid = refid;
}
@Override
public String getSQL(Object object) {
SQLNode sqlnode = node.getSQLNode(refid);
return sqlnode.getSQL(object);
}
}
其它的xml标签类似,完成最终的sql
调用AbstractSQLStatementNode.getSQL方法,参数为客户端传入参数
XML例子如下:
[html] view plain
<select id="findPage" parameterType="java.util.Map" resultMap="ORG">
SELECT * FROM XT_ORG WHERE BDELETE<>1 <if test="name != null"> AND NAME=#{name}</if> LIMIT #{OFFSET}, #{ROWS}
</select>
根据是否传入了name,即可成功执行出最终的sql
SELECT * FROM XT_ORG WHERE BDELETE<>1 AND NAME=#{name} LIMIT #{OFFSET}, #{ROWS}
再解析SQL得到,并提出参数
SELECT * FROM XT_ORG WHERE BDELETE<>1 AND NAME=? LIMIT ?,?
即可生成最终的PrepareStatement