使用 Mybatis 真心不要偷懒

  前言
  
  这篇文章非常简单,没有什么高深技术。这些细节用过Mybatis的童鞋都知道。写这篇文章的缘由是:在最近的工作中,接手了一个外包项目,发现项目中 mapper 文件全部是自动生成的,代码十分冗余且不易维护,用知乎上的回答,这算得上是名副其实的”屎山”代码了。现在用 Mybatis做持久层算是Java系的主流,其中有一个主要的原因就是灵活性,但通过代码生成工具恰恰打破它的灵活性,生成一堆冗余且无用的代码,方法的命名也十分奇怪,总之,简直就是灾难。前者一时爽,后者呜呼哀哉,特别是上线后,那就更可怕了,到底改还是不改呢?不改强迫症,看着就不舒服,一改就要花费成倍的时间,仿佛是生产事故在像你招手。so,本着程序员本是同根生的原则,真心建议大家不要使用生成工具。前期的一点点时间的节省,后期真的就需要成倍的时间。
  
  自动生成代码的若干宗罪:
  
  SQL怎么优化?
  
  命名不规范如何修改?
  
  冗余代码怎么办?常常是为了一个代码,生成一堆代码。
  
  参数可理解性?
  
  …
  
  传参方式
  
  1. 使用 _parameter 关键字
  
  接口:
  
  List<Address> queryAddressBySimplte(String address,String coinType);
  
  XML文件:
  
  <sql id="querySQL">
  
  select oid, party_id, coin_type, address,address_alias,address_type, wallet_id,
  
  user_id, status, register_time, created_time, update_time from t_molecule_address
  
  </sql>
  
  <select id="queryAddressBySimplte" resultType="Address">
  
  <include refid="querySQL"/> where
  
  <if test="_parameter!=null and _parameter!=''">
  
  address=#{0}
  
  </if>
  
  <if test="_parameter!=null and _parameter!=''">
  
  and coin_type=#{1}
  
  </if>
  
  </select>
  
  其中_parameter 参数表示参数对象,其内部数据结构为:MapperParamMap 。按照index进行参数值的获取。
  
  注意事项:
  
  当方法是单个参数时,可以直接使用 #{_parameter} 进行获取。
  
  当方法有多个参数时,则不能直接使用 #{_parameter} 方式,必须通过Index的形式进行获取,#{0} 表示第一个参数,#{1} 表示第二个参数。
  
  当方法为多个参数时使用 #{_parameter} 时。日志显示如下所示:
  
  DEBUG main - ==> Preparing: select oid, party_id, coin_type, address,address_alias,address_type, wallet_id, user_id, status, register_time, created_time, update_time from t_molecule_address where address=? and coin_type=?
  
  2019-05-07 13:24:31 DEBUG main - ==> Parameters: {0=0xbfa8f58ebea6e0643a5370c555a5bacfe320fd72, 1=ETH, param1=0xbfa8f58ebea6e0643a5370c555a5bacfe320fd72, param2=ETH}(MapperParamMap)
  
  优点:
  
  暂时没想出来啥优点。(知道的可以在评论区留言补充)。
  
  缺点:
  
  多个参数时,只能通过角标的形式引入,可读性,以及可理解性比较差。
  
  传参时,不同参数数量其规则不同,容易出错。
  
  代码生成工具使用的比较多,我相信很少有人主动用这种方式。
  
  2. 使用@Param 注解
  
  接口:
  
  List<Address> queryAddressBySimplte(@Param("address")String address,@Param("coinType") String coinType);
  
  XML文件
  
  <sql id="querySQL">
  
  select oid, party_id, coin_type, address,address_alias,address_type, wallet_id,
  
  user_id, status, register_time, created_time, update_time from t_molecule_address
  
  </sql>
  
  <select id="queryAddressBySimplte" resultType="Address">
  
  <include refid="querySQL"/> where
  
  <if test="_parameter!=null and _parameter!=''">
  
  address=#{address}
  
  </if>
  
  <if test="_parameter!=null and _parameter!=''">
  
  and coin_type=#{coinType}
  
   # -*- coding: utf-8 -*-
"""
Created on Wed May 8 08:25:40 2019

@author: Li Kangyu
"""

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.contrib.learn.python.learn.datasets.mnist import read_data_sets
import time
# 数据集下载地址:http://www.chenghgongs.com yann.lecun.com/exdb/mnist/


MINIBATCH_SIZE = 100
NUM_HD = 100
data = read_data_sets('MNIST_DATA',one_hot=True)

x = tf.placeholder(tf.float32,[None,784])
y_true = tf.placeholder(tf.float32,[None,10])

def nn_model(x):
hidden_layer = {
'w':tf.Variable(tf.zeros([784,NUM_HD])),
'b':tf.Variable(tf.zeros([NUM_HD]))
}
output_layer = {
'w':tf.Variable(tf.zeros([NUM_HD,10])),
'b':tf.Variable(tf.zeros([10]))
}

z1 = tf.matmul(x,hidden_layer[www.yunyouuyL.com'w']) + hidden_layer['b']
a1 = tf.nn.relu(z1)

output = tf.matmul(a1,output_layer['w']) + output_layer['b']

return output

def train_nn(x):
y_pred = nn_model(x)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y_pred,labels=y_true))
optimizer = tf.train.AdamOptimizer(www.hnxinhe.cn).minimize(cost)

correct_mask = tf.equal(tf.argmax(y_pred,1),tf.argmax(y_true,1))
accuracy = tf.reduce_mean(tf.cast(correct_mask,tf.float32))

NUM_STEPS = 100

with tf.Session(baihuiyulegw.com) as sess:
sess.run(tf.initialize_all_variables(www.tianjiuyule178.com ))
for epoch in range(NUM_STEPS):
epoch_loss = 0
num_minibatch = int(data.train.num_examples/MINIBATCH_SIZE)
for _ in range(num_minibatch):

batch_xs,batch_ys = data.train.next_batch(MINIBATCH_SIZE)
_,loss = sess.run([optimizer,cost],feed_dict={x:batch_xs,y_true:batch_ys})
epoch_loss += loss / num_minibatch
if epoch % 10 ==0:
print("Epoch = ",epoch,"loss www.chenhaiyulp.cn/= ",epoch_loss)

ans = sess.run(accuracy,feed_dict={x:data.test.images,
y_true:data.test.labels})

print("Accuracy:{:.4}%".format(ans*100))

train_nn(x)
  
  </select>
  
  注意事项:
  
  在XML文件中的参数名与@Param()中的参数名一致,与方法参数名无关。
  
  例如:
  
  List<Address> queryAddressBySimplte(@Param("addressAlias")String address,@Param("coinTypeAlias") String coinType);
  
  这时我们在XML文件中,对应的参数应该为:
  
  <select id="queryAddressBySimplte" resultType="Address">
  
  <include refid="querySQL"/> where
  
  <if test="_parameter!=null and _parameter!=''">
  
  address=#{addressAlias}
  
  </if>
  
  <if test="_parameter!=null and _parameter!=''">
  
  and coin_type=#{coinTypeAlias}
  
  </if>
  
  </select>
  
  使用注解时,我们还可以 params 方式。
  
  例如:
  
  <select id="queryAddressBySimplte" resultType="Address">
  
  <include refid="querySQL"/> where
  
  <if test="param1!=null and param1!=''">
  
  address=#{param1}
  
  </if>
  
  <if test="param2!=null and param2!=''">
  
  and coin_type=#{param2}
  
  </if>
  
  </select>
  
  其中 param1 表示第一个参数,param2 表示第二个参数。当然了,不推荐大家这么用,因为对可读性以及可理解性都不友好。
  
  优点:
  
  代码可读性好,参数自可读。
  
  可重命名参数名。
  
  缺点:
  
  需要引入@Param 注解 (当然,我不认为这是缺点)。
  
  可扩展性较弱。(超过3个参数的方法,就不建议使用该方法了)。
  
  3. 使用 Java 对象
  
  Domain对象(省略Get / Set 方法):
  
  public class Address {
  
  /**
  
  * 币种类型
  
  */
  
  private String coinType;
  
  /**
  
  * 地址
  
  */
  
  private String address;
  
  ...
  
  接口:
  
  List<Address> queryAddressBySimplte(Address address);
  
  XML文件:
  
  <select id="queryAddressBySimplte" resultType="Address" parameterType="Address">
  
  <include refid="querySQL"/> where
  
  <if test="address!=null and address!=''">
  
  address=#{address}
  
  </if>
  
  <if test="coinType!=null and coinType!=''">
  
  and coin_type=#{coinType}
  
  </if>
  
  </select>
  
  其中参数为 Address 对象中的属性即可。如果参数为非对象属性中的参数,即会显示以下异常:
  
  org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'coinType11' in 'class io.invault.molecule.dal.domain.address.Address'
  
  优点:
  
  可扩展性好。
  
  参数名与对象列明一致,理解性好。
  
  缺点:
  
  需要另外引入一个Java实体对象。(其实这是与可扩展性矛盾的地方)。
  
  小结
  
  通过上述几种传参方式,我们已经非常清楚每一种方式的应用场景以及优缺点。如果要说最佳的方式,还得回归到Java规范上来。在Java手册中,有这么一条,建议超过3个参数及以上方法,改用参数对象传递。在上述例子中,我们同样遵守这样的规范是极好的。总之,我们应该明白:代码是给人读的,而不是计算机!。

猜你喜欢

转载自www.cnblogs.com/qwangxiao/p/10830481.html
今日推荐