Mybatis的学习(二)
1.操作数据库的两种方式以及传值
1.1 xml
步骤:
在mybatis的核心配置(mybatis.xml)的文件之上创建一个Mapper(mapper.xml映射文件),创建mapper标签,在标签内创建namespace属性并赋值(用来区分表空间),一般用类名命名,然后在mapper标签内就可以添加select、insert、delete、update标签,再使用这些标签是需要给它们创建一个id(session调用的唯一标识码),值可以随意填写但是一般用方法名,并且还要设置resultType属性(用来定义返回值类型,调用有返回值的方法必须要有),最后就可以在标签内写sql语句了!(要手动提交commit())。测试类调用方式:session.操作数据的动作(“id”,[传入的值])
传值方式(重点):
传值方式根据传递数据的方式区分,用数组传值,可以通过下标取值,需要注意的是:下标从0开始、下标的顺序,格式:#{下标}
用map集合传值,通过键取值,格式:#{键名}。,插入值时需要注意键名需和数据库列名一致。
用实体类对象传值,取值方法同map,但是键名是属性名
补充:
除了以上取值方式,还可用el表达式取值,它们本质的区别是#使用了占位符(较安全),$(el)没有使用占位符直接替换(如果是字符串,需要注意符号问题)
1.2 注释
配置好mybatis的核心配置(mybatis.xml)就可以使用方式,使用方式@数据库操作动作(“sql语句”)(如:@Select(“select * from food”)), 测试类调用方式:session.getMapper(接口.class),需要手动commit。
2.接口映射
将操作动作放在接口中,而不是session中
步骤:
基于xml:声明方式同xml方式一样,需要注意的是namespace的值是接口全路径,id的值是方法名,传值后取值的方法是#{param1(代表接口方法中的第一个形参)},如果不想使用param可以将注解@Param加在形参自定义键名,需要注意接口方法中的形参是按序排列的,引用时注意顺序 。也可用#{下标}取值。
基于注解:与xml方式唯一的不同点是没有映射文件,所以要将mybatis的配置文件中的mapper的resources属性改为class,class的值是需要映射的接口全路径(类用“.”,文件用“/”),sql语句直接写在注解里,取值方式同xml
3.利用log4j打印调试日志
需要的jar包:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
Log4j日志分为5中级别(级别从小到大):off、debug 调试(开发阶段)、info运行消息(测试或者运行阶段)、warn警告消息、error程序错误消息、fatal系统错误消息、all,如果全局控制设置了级别,小于这个级别的级别都不会打印,反之则打印,mybatis的全局控制级别是info,所以要想使用debug级别,需要将全局控制级别改为debug
Mybatis全局控制的设置,在跟目录创建一个log4j.properties文件。
文件内容:
### set log levels ###
#设置权限
log4j.rootLogger = debug , stdout
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
#设置输出方式
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#设置输出格式
log4j.appender.stdout.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
4.typeAliases(别名)
当返回值路径太长时,这是我们就可以用typeAliases给它一个别名。默认每个数据类型都有一个别名,具体可在TypeAliasRegistry类查询。可以定义多个。
第二种定义别名的方法:给某个包下的类都起一个别名,别名的命名规则为类名首字母小写。
<typeAliases>
<package name="需要取别名的包路径"/>
</typeAliases>
自定义:在mybatis.xml定义
<typeAliases>
<typeAlias type="类全路径" alias="别名"></typeAlias>
</typeAliases>
registerAlias("string", String.class);
registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class);
registerAlias("byte[]", Byte[].class);
registerAlias("long[]", Long[].class);
registerAlias("short[]", Short[].class);
registerAlias("int[]", Integer[].class);
registerAlias("integer[]", Integer[].class);
registerAlias("double[]", Double[].class);
registerAlias("float[]", Float[].class);
registerAlias("boolean[]", Boolean[].class);
registerAlias("_byte", byte.class);
registerAlias("_long", long.class);
registerAlias("_short", short.class);
registerAlias("_int", int.class);
registerAlias("_integer", int.class);
registerAlias("_double", double.class);
registerAlias("_float", float.class);
registerAlias("_boolean", boolean.class);
registerAlias("_byte[]", byte[].class);
registerAlias("_long[]", long[].class);
registerAlias("_short[]", short[].class);
registerAlias("_int[]", int[].class);
registerAlias("_integer[]", int[].class);
registerAlias("_double[]", double[].class);
registerAlias("_float[]", float[].class);
registerAlias("_boolean[]", boolean[].class);
registerAlias("date", Date.class);
registerAlias("decimal", BigDecimal.class);
registerAlias("bigdecimal", BigDecimal.class);
registerAlias("biginteger", BigInteger.class);
registerAlias("object", Object.class);
registerAlias("date[]", Date[].class);
registerAlias("decimal[]", BigDecimal[].class);
registerAlias("bigdecimal[]", BigDecimal[].class);
registerAlias("biginteger[]", BigInteger[].class);
registerAlias("object[]", Object[].class);
registerAlias("map", Map.class);
registerAlias("hashmap", HashMap.class);
registerAlias("list", List.class);
registerAlias("arraylist", ArrayList.class);
registerAlias("collection", Collection.class);
registerAlias("iterator", Iterator.class);
registerAlias("ResultSet", ResultSet.class);
5.selectKey
当使用插入语句时,主键可用序列的nextval方法,但是有时我们需要在程序获取到主键,所以要用selectKey提前将主键定义好,以便以后使用。
Xml:
<insert id="saveFood">
<selectKey keyProperty="要赋值类的属性" order="BEFORE" resuletType= "返回类属性的类型" statementType="STATEMENT">
select 序列名.Nextval from dual
</selectKey>
insert into food(FOODID,FOODNAME,PRICE) values(#{foodid},#{foodname},#{price}(如果使用类传值使用属性名,如果用map传值使用键名))
</insert>
注解:
@SelectKey(before=true,keyProperty=”属性名”,reslutType=”属性的类型”,statement=” select 序列名.Nextval from dual”)
@Insert(“sql语句”)
6.select调用存储过程
**jdbcType可以查看数据库类型在java中的写法**
关键代码:
Java:
public class ProTest {
public static SqlSession getSession() throws IOException{
String resource = "lesson02/proc/mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
return sqlSessionFactory.openSession();
}
@Test
public void pTest() throws IOException{
SqlSession session= getSession();
Map map = new HashMap();
map.put("p1", 123);
map.put("p2", 456);
map.put("p3", 0);
session.selectOne("call_prg_add",map);
System.out.println(map.get("p3"));
}
@Test
public void fTest() throws IOException{
SqlSession session= getSession();
Map map = new HashMap();
map.put("p1", 123);
map.put("p2", 456);
map.put("p3", 0);
session.selectOne("call_fun_add",map);
System.out.println(map.get("p3"));
}
}
Mapper.xml(映射文件):
<mapper namespace="proTest">
<!-- jdbc调用存储过程
{call 存储过程名(?,?)}
调用函数
{?=call 函数名(?,?)}
-->
<select id="call_prg_add" statementType="CALLABLE">
{call prg_add(
#{p1,mode=IN,jdbcType=NUMERIC},
#{p2,mode=IN,jdbcType=NUMERIC},
#{p3,mode=OUT,jdbcType=NUMERIC})}
</select>
<select id="call_fun_add" statementType="CALLABLE">
{#{p3,mode=OUT,jdbcType=NUMERIC}=call fun_add(
#{p1,mode=IN,jdbcType=NUMERIC},
#{p2,mode=IN,jdbcType=NUMERIC})}
</select>
</mapper>